typescript 当类实现接口时,类型脚本不正确的类型推断

bq9c1y66  于 7个月前  发布在  TypeScript
关注(0)|答案(2)|浏览(82)

当在类型脚本中使用组合方法而不是继承方法时,我想根据实体的“能”而不是它们的“是”来描述我的实体。为了做到这一点,我需要创建一些复杂的接口,然后为我的类(我使用类是为了不创建手动原型链,也不破坏我认为存在于js引擎中的一些优化)来实现我的接口。但是当方法的类型没有被正确推断时,这会导致奇怪的行为。相反,当使用对象并声明它们是相同的接口类型时,一切都按预期工作。
所以我使用VSCode与typescript 3.6.3.我已经创建了接口的2d形状应该有方法返回所有法线的边缘.然后我创建类实现该接口,我希望它需要这个方法,它应该有相同的返回类型(这部分工作)和相同的参数类型我的问题是,我不想仅仅为了获得一致的VSCode行为而手工创建原型链。
此外,当在控制台中运行tsc时,我在类方法中获得了相同的错误,因为参数是“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];
  }
};

字符串
我的tsz.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中是不可实现的,我应该求助于手写的(哦,亲爱的......)原型链和简单的原型对象吗?”
    在此先谢谢您!
cld4siwp

cld4siwp1#

这是TypeScript中的一个设计限制(参见ms/TS#1373)。在ms/TS#6118上尝试过修复,但它与现有的真实世界代码有一些糟糕的/破坏性的交互,所以他们放弃了它。在ms/TS#32082上有一个开放的问题,要求更好的东西,但目前没有任何有用的东西。
这里的建议是在实现/扩展类时手动注解参数类型;这比依靠手写的原型链更好,尽管更烦人。

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 [];
  }
}


这是因为方法参数contravariance是类型安全的..
无论如何,希望这能有所帮助;祝你好运!
链接到代码

hpxqektj

hpxqektj2#

作为一种解决方法,您可以使用Parameters实用程序类型从另一个接口提取参数。当使用单个对象作为函数参数(相对于位置参数)并且您的方法的参数可能经常更改时,这很有用。
举例来说:

interface Foo {
  method(args: { arg1: string, arg2: number}): void;
}

class Bar implements Foo {
  method({ arg1, arg2 }: Parameters<Foo['method']>[0]): void {
    // arg1 and arg2 types will be correctly inferred
  }
}

字符串
如果你有几个方法需要重新声明,你可以为一个特定的类创建你自己的实用程序类型:

interface Foo {
  method(args: { arg1: string, arg2: number}): void;
}

type FooArgs<Method extends keyof Foo> = Parameters<Foo[Method]>[0];

class Bar implements Foo {
  method({ arg1, arg2 }: FooArgs<'method'>): void {
    // arg1 and arg2 types will be correctly inferred
  }
}


希望能帮上忙。

相关问题