我一直在困惑以下代码中的TypeScript编译器错误2322。
function broken<A extends {a: number}>() {
const foo: A = {a: 1}; // unexpected error: [ts] Type '{ a: number; }' is not assignable to type 'A'. [2322]
console.log (foo);
}
如果类型是非泛型的,则类似的代码可以编译而不会出错。
function works() {
interface A {a: number};
const foo: A = {a: 1}; // no compiler error, as expected
console.log (foo);
}
为什么第一个函数无法编译?我认为我对接口和通用约束之间的区别有一些误解。
答案 0 :(得分:0)
一段时间后,我意识到了问题所在。将TypeScript错误2322转换为简单的英语,这意味着:“ 您正在尝试设置A
的值,该值具有数字属性a
,但可能还具有其他属性(!!!),到仅具有数字属性a
的对象文字。由于该对象文字缺少A的其他(潜在)属性,分配失败。“ < / p>
为说明问题,想象一下用实型替换A:
interface A { a: number; b: string; };
const foo: A = { a: 1 }; // compiler error, as expected
如果通用类型是特定类型,则满足通用约束的任何可能类型(“具有数字属性a
”)都可以工作时,编译器将引发错误。
理论上,通过检查生成的foo
是否可能在以后的代码中引起问题,在这种情况下TypeScript可能会更聪明。例如,如果您对foo
所做的唯一事情就是使用其a
属性,而您没有返回对foo
进行超出其约束范围的任何操作,例如将其传递给接受A
的其他函数。
但是TypeScript似乎还不那么聪明-它没有考虑到代码的未来。而是在分配时检查是否所有可能的右侧类型都满足左侧类型的约束。如果不是,则抛出错误。
如果您确定代码不会引起问题(例如,因为您传入的值不只是扩展A
,那么它实际上 是{ {1}}),然后可以将值强制转换为A,这样分配就可以了。这是调用外部API(例如数据库)时的一种常见模式,该API可能会返回无类型的JSON,您可以将该类型转换为您知道的类型。像这样:
A
或者您可以决定将其从通用函数更改为非通用函数。像这样:
function alsoWorks1<A extends {a: number}>() {
const foo: A = {a: 1} as A;
console.log (foo);
}