在typescript类中键入推断

时间:2018-03-04 17:53:43

标签: typescript type-inference

我希望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的类型是任何类型的问题都存在同样的问题。

为什么类型推断在这里不起作用?我该怎么做才能让它发挥作用?

3 个答案:

答案 0 :(得分:6)

这里没有类型推断。父类或实现的接口不会推断成员类型。 arg不是推断 string,而是隐式 any

子类有机会覆盖方法签名,只要它与父方法兼容即可。可以将方法定义为viewer(arg: any) {...}。由于stringany,的子集,因此将允许viewer(arg: boolean) {...},而viewer(arg) {...}则不允许。

any会导致arg隐式viewer(arg: any) {...},与strict相同。它将在松散的编译器模式下工作,但会导致noImplicitAnynoImplicitAny编译器选项出现类型错误。 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项目提出一个建议。