如何扩展一个不能在Typescript中修改的接口类型?



当我尝试在Typescript中增加一个接口时,我得到了这个错误:

'BasketballPlayer' only refers to a type, but is being used as a value here.

例如:

我在库中有一个不能修改的BasketballPlayer类型。

interface BasketballPlayer extends Player {
run(speed: number): boolean
}

创建BasketballPlayer实例时,我会这样做:

const playerFactory = new PlayerFactory();
// The PlayerFactory returns the base Player type.
// I will then need to cast the returned instance to the BasketballPlayer type.
const basketballPlayer = playerFactory.getPlayer("BasketballPlayer") as BasketballPlayer;

我想在BasketballPlayer类型实例化时添加一个名为dunk的附加函数。我是这样做的:

declare module "./generated/library" {
interface BasketballPlayer {
dunk(strength: number): Promise<boolean>;
}
}
// However, Typescript will complain that "'BasketballPlayer' only refers to a type, but is being used as a value here.""
// But I cannot augment PlayerConcrete instead because only BasketballPlayer will have `dunk`, not all Player(s).
BasketballPlayer.prototype.dunk = async function(strength: number): Promise<boolean> {
// Do the dunk logic
return true;
}

既然我没有控制库文件,我怎么能增加BasketballPlayer接口类型?我很确定,当使用BasketballPlayer接口时,它总是有一个实际的实例。

tl;dr只有当底层主题是类而不是接口时,原型增强才合适。接口在JavaScript中是不存在的(也就是说,在运行时将被编译掉),而类是一个构造,它将在JavaScript中携带一个原型对象,因此可以存储在运行时使用的函数定义之类的东西


从你的描述来看,我们在你的第三方库中定义了以下接口和类

library.ts

interface Player {
name: string // abritrary property added for demo purposes
}
class PlayerConcrete implements Player {
name: string = ''
}
interface BasketballPlayer extends Player {
run(speed: number): boolean
}

如果您只是对覆盖接口本身感兴趣,那么您的初始模块重新声明逻辑就足够了:

augment.ts

import { BasketballPlayer } from './generated/library'
declare module "./generated/library" {
interface BasketballPlayer {
dunk(strength: number): Promise<boolean>;
}
}

component.ts

import { BasketballPlayer, PlayerConcrete } from './generated/library'
import './augment.ts'
class BasketballPlayerConcrete extends PlayerConcrete implements BasketballPlayer {
run = (speed: number) => // do the run logic;
}
// Error: Property 'dunk' is missing in type 'BasketballPlayerConcrete' but required in type 'BasketballPlayer'.(2420)
class BasketballPlayerConcrete extends PlayerConcrete implements BasketballPlayer {
run = (speed: number) => // do the run logic;
dunk = (strength: number) => // do the dunk logic;
}
// valid
const basketballPlayer: BasketballPlayer = new BasketballPlayerConcrete()

因为没有现有的BasketballPlayerConcrete类定义在你的library.ts,没有必要覆盖任何原型,因为你将定义你的类(因此dunk函数的实现)在另一个文件,你控制,例如component.ts。但是,如果BasketballPlayerConcrete确实存在于library.ts中,我们可以继续使用您使用的方法

library.ts

// ... same as previous
class BasketballPlayerConcrete extends PlayerConcrete implements BasketballPlayer {
run = (speed: number) => // do the run logic;
}

augment.ts

// ... same as previous
import { BasketballPlayerConcrete } from './generated/library'
BasketballPlayerConcrete.prototype.dunk = function(strength: number): Promise<boolean> {
// do the dunk logic
}

component.ts

import { BasketballPlayer, BasketballPlayerConcrete } from './generated/library'
import './augment.ts'
const basketballPlayer: BasketballPlayer = new BasketballPlayerConcrete()

最新更新