当在类型脚本中使用组合方法而不是继承方法时,我想根据实体的“能”而不是它们的“是”来描述我的实体。为了做到这一点,我需要创建一些复杂的接口,然后为我的类(我使用类是为了不创建手动原型链,也不破坏我认为存在于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中是不可实现的,我应该求助于手写的(哦,亲爱的......)原型链和简单的原型对象吗?”
在此先谢谢您!
2条答案
按热度按时间cld4siwp1#
这是TypeScript中的一个设计限制(参见ms/TS#1373)。在ms/TS#6118上尝试过修复,但它与现有的真实世界代码有一些糟糕的/破坏性的交互,所以他们放弃了它。在ms/TS#32082上有一个开放的问题,要求更好的东西,但目前没有任何有用的东西。
这里的建议是在实现/扩展类时手动注解参数类型;这比依靠手写的原型链更好,尽管更烦人。
字符串
请注意,
v
实际上可能是any
或unknown
,而getNormals()
将是正确的实现:型
这是因为方法参数contravariance是类型安全的..
无论如何,希望这能有所帮助;祝你好运!
链接到代码
hpxqektj2#
作为一种解决方法,您可以使用
Parameters
实用程序类型从另一个接口提取参数。当使用单个对象作为函数参数(相对于位置参数)并且您的方法的参数可能经常更改时,这很有用。举例来说:
字符串
如果你有几个方法需要重新声明,你可以为一个特定的类创建你自己的实用程序类型:
型
希望能帮上忙。