考虑以下Typescript代码:
class OrderFixture {
orderId: string;
constructor() {
this.orderId = "foo";
}
}
class DecisionFixture {
decisionId: string;
constructor() {
this.decisionId = "bar";
}
}
class FixtureStore {
order = () => new OrderFixture();
decision = () => new DecisionFixture();
}
const fixtureStore = new FixtureStore();
export function getFixture<
K extends keyof FixtureStore,
T extends ReturnType<FixtureStore[K]>
>(entityName: K): T {
return fixtureStore[entityName](); // ERROR: Type 'OrderFixture' is not assignable to type 'T'.
}
它会产生以下类型的错误:
Type 'OrderFixture | DecisionFixture' is not assignable to type 'T'.
'OrderFixture | DecisionFixture' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint 'OrderFixture | DecisionFixture'.
Type 'OrderFixture' is not assignable to type 'T'.
'OrderFixture' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint 'OrderFixture | DecisionFixture'.ts(2322)
这是一个操场。
对于这类错误提出的问题,似乎有一个相当规范的答案,但我看不出其中列出的两个原因与我的代码之间有任何相关的相似之处。
如果我像这个答案中建议的那样强制将返回值强制转换为T
,那么在调用getFixture
时我会得到正确的类型。为什么Typescript不能为我推断出这些类型?
Typescript在这里的错误消息是完全描述性的:您的函数返回可分配给OrderFixture | DecisionFixture
但不可分配给它的任意子类型的东西,例如OrderFixture & HTMLCanvasElement
。如果您仍然不确定,请考虑以下代码,其中您的函数承诺返回这样的东西;它显然不是类型安全的,但它没有错误,因为它只使用了函数声称具有的返回类型。
let canvas = getFixture<'order', OrderFixture & HTMLCanvasElement>('order');
let ctx = canvas.getContext('2d');
通常,正是出于这个原因,您不应该有一个只出现在返回位置的类型参数,因为它允许调用方期望一个特定的类型,而不传递任何允许函数知道它应该返回什么类型的参数。在您的情况下,不需要类型参数T
:只需直接将ReturnType<FixtureStore[K]>
作为函数的返回类型即可。
也就是说,在这种情况下,有一些可疑的事情似乎确实是Typescript的错:即使拆分函数的逻辑并提供类型注释来帮助编译器,Typescript仍然会出错。
function getFixture<K extends keyof FixtureStore>(entityName: K): ReturnType<FixtureStore[K]> {
let factory: FixtureStore[K] = fixtureStore[entityName];
// error here
let instance: ReturnType<typeof factory> = factory();
return instance;
}}
游乐场链接
从逻辑上讲,Typescript永远不应该抱怨factory()
的类型可能不可分配给ReturnType<typeof factory>
,但在这里它恰恰抱怨了这一点。因此,我认为这应该由了解Typescript内部结构的人来研究,并可能作为问题跟踪器上的一个bug提出。