我希望arg
param能够从父类中推断出类型
export abstract class IEngineClas {
abstract viewer(arg: string): boolean
}
export class MyClass extends IEngineClas {
viewer(arg) {
return true
}
}
然而在实践中,编译器抱怨arg
具有隐式类型。
我也试过接口
export interface IEngine {
viewer?: (arg: string) => boolean
}
export class MyClass implements IEngine {
viewer(arg) {
return true
}
}
编译器思维arg
的类型是任何类型的问题都存在同样的问题。
为什么类型推断在这里不起作用?我该怎么做才能让它发挥作用?
答案 0 :(得分:6)
这里没有类型推断。父类或实现的接口不会推断成员类型。 arg
不是推断 string
,而是隐式 any
。
子类有机会覆盖方法签名,只要它与父方法兼容即可。可以将方法定义为viewer(arg: any) {...}
。由于string
是any,
的子集,因此将允许viewer(arg: boolean) {...}
,而viewer(arg) {...}
则不允许。
any
会导致arg
隐式viewer(arg: any) {...}
,与strict
相同。它将在松散的编译器模式下工作,但会导致noImplicitAny
或noImplicitAny
编译器选项出现类型错误。 any
特别有助于避免在此类情况下意外推断New-WinUserLanguageList
。
答案 1 :(得分:5)
您当然可以推断!
Typescript 具有有史以来功能最强大的通用系统!
它只是需要一些神秘的语法。
您可以这样写(check it on Typescript Playground):
export abstract class IEngineClas {
abstract viewer(arg: string): boolean
}
export class MyClass extends IEngineClas {
viewer(arg: IEngineClas["viewer"] extends (arg: infer U) => any ? U : any) {
return true
}
}
let test = (new MyClass()).viewer("hop") // Type OK
let test2 = (new MyClass()).viewer(1) // Wrong type
IEngineClas["viewer"]
可以检索父函数的类型:(arg:string) => boolean
使用conditional types,您可以使用 infer 关键字将其分配给泛型,以检索所需的arg。
这样阅读:如果IEngineClas["viewer"]
的类型为(arg: U) => any
(带有自变量的函数),请抓住U
的类型(第一个自变量)并将其用作参数arg
的类型。否则,请使用类型any
。
一种更好的书写方式,类型为 (check it on Typescript Playground):
type firstArg<T> = T extends (arg: infer U) => any ? U : any
export abstract class IEngineClas {
abstract viewer(arg: string): boolean
}
export class MyClass extends IEngineClas {
viewer(arg: firstArg<IEngineClas["viewer"]>) {
return true
}
}
let test = (new MyClass()).viewer("hop") // Type OK
let test2 = (new MyClass()).viewer(1) // Wrong type
在另一种情况下,我有一天问为什么与抽象类有关的这些预期推断行为不是默认行为,并回答这是由于性能问题引起的。我承认在大型项目中, Typescript 变得非常慢。即使会欢迎在抽象类上激活键入或不激活键入的编译标志。
我问过的帖子:https://github.com/Microsoft/TypeScript/issues/21428
如果您只是想摆脱隐含任何警告,只需明确指定any
类型:viewer(arg:any)
,或禁用 noImplicitAny 在编译器选项中标记。
答案 2 :(得分:3)
没有一个很好的方法来做到这一点。最接近和最简单的方法是implement
一个接口(或一个类,也可以实现抽象类,但是您松散的共享代码)是使用函数字段并将其键入为:
export abstract class IEngineClas {
abstract viewer(arg: string): boolean
}
export class MyClass implements IEngineClas {
viewer: IEngineClas['viewer'] = function (this: MyClass, arg) { // we need to be explicit about who this is
return true;
}
}
这样做的缺点是,该函数是分配给每个实例的,而不是分配给原型的,因此您也使用super
。
如果您对此有强烈的看法,我会为GitHub项目提出一个建议。