类实现接口时Typescript错误的类型推断

时间:2019-10-06 09:55:45

标签: typescript class methods interface implements

当在打字稿中使用组合方法而不是继承一个时,我想根据它们的“可以”而不是它们的“是”来描述我的实体。为了做到这一点,我需要创建一些复杂的接口,然后为我的类(我使用类是为了不创建手动原型链,并且不破坏我认为存在于js引擎中的某些优化)以实现我的接口。但是,如果无法正确推断方法的类型,则会导致奇怪的行为。相反,当使用对象并声明它们具有相同的接口类型时,一切都会按预期进行。

所以我将VSCode与打字稿3.6.3配合使用。我已经为2D形状创建了接口,该接口应具有将所有法线返回到边缘的方法。然后,我创建实现该接口的类,并期望它需要此方法,并且它应具有相同的返回类型(此部分有效)和相同的参数类型(此参数没有)。参数被推断为任意。我的问题是我不想只为了获得一致的VSCode行为而手工创建原型链。

同样在控制台中运行 tsc 时,在访问不存在的prop时,类方法中的参数为“ any”类型的参数和对象方法中的预期错误也得到相同的错误

interface _IVector2 {
  x: number;
  y: number;
}

interface _IShape2D {
  getNormals: ( v: string ) => _IVector2[];
}

export class Shape2D implements _IShape2D {
  getNormals( v ) {
    console.log( v.g );
                   ^ ----- no error here

    return [{} as _IVector2];
  }
}

export const Test: _IShape2D = {
  getNormals( v ) {
    console.log( v.g );
                   ^------ here we get expected error that  
                   ^------ 'g doesn`t exist on type string'

    return [{} as _IVector2];
  }
};

我的tsconfig.json

{
  "compilerOptions": {
    "target": "es2017",
    "allowSyntheticDefaultImports": true,
    "checkJs": false,
    "allowJs": true,
    "noEmit": true,
    "baseUrl": ".",
    "moduleResolution": "node",
    "strict": true,
    "strictNullChecks": true,
    "noImplicitAny": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "noImplicitReturns": true,
    "noImplicitThis": true,
    "noFallthroughCasesInSwitch": true,
    "jsx": "react",
    "module": "commonjs",
    "alwaysStrict": true,
    "forceConsistentCasingInFileNames": true,
    "esModuleInterop": true,
    "noErrorTruncation": true,
    "removeComments": true,
    "resolveJsonModule": true,
    "sourceMap": true,
    "watch": true,
    "skipLibCheck": true,
    "paths": {
      "@s/*": ["./src/*"],
      "@i/*": ["./src/internal/*"]
    }
  },
  "exclude": [
    "node_modules"
  ]
}

预期:
-类方法的参数应推断为字符串
实际:
-方法的参数可以推断为任何

最终我的问题如下: “这种行为在ts中是无法实现的,我应该求助于手写的(哦,亲爱的...)原型链和原型的简单对象吗?”

提前谢谢!

1 个答案:

答案 0 :(得分:0)

这是TypeScript中的design limitation。有一个fix attempted,但它与现有的现实世界代码存在一些不良/中断的交互,因此它们gave up on it

此时的建议是在实现/扩展类中手动注释参数类型。尽管比较烦人,但这比求助于手写原型链要好。

export class Shape2D implements _IShape2D {
  getNormals(v: string) { // annotate here
    console.log(v.g); // <-- error here as expected
    return [{} as _IVector2];
  }
}

请注意,v的确可以是anyunknown,而getNormals()是正确的实现:

export class WeirdShape implements _IShape2D {
  getNormals(v: unknown) { // okay
    return [];
  }
}

这是由于method parameter contravariance是类型安全的……WeirdShape仍然是完全有效的_IShape2D。因此,虽然将参数推断为string,但没有什么不正确关于它更通用。

无论如何,希望能有所帮助;祝你好运!

Link to code