令人困惑的“[ts] Type ... is not assignable to type [2322]”约束泛型函数中的错误
Confusing "[ts] Type ... is not assignable to type [2322]" errors inside constrained generic function
我一直对下面代码中的 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);
}
为什么第一个函数编译失败?我想我误解了一些关于接口和通用约束之间区别的基本知识。
过了一会儿我意识到了这个问题。将 TypeScript 错误 2322 翻译成简单的英语,它的意思是:“你试图设置 A
的值,它有一个数字 属性 a
但它也可能有额外的属性 (!!!),到一个只有数字 属性 a
的对象字面量。因为这个对象字面量缺少其他(潜在的)属性A的,赋值失败。"
为了说明问题,想象一下用真实类型替换 A:
interface A { a: number; b: string; };
const foo: A = { a: 1 }; // compiler error, as expected
如果满足泛型约束 ("has a numeric property a
") 的任何可能类型在泛型类型是特定类型的情况下工作,编译器将抛出错误。
理论上,在这种情况下,TypeScript 可以更智能地检查生成的 foo
是否可能在代码的后面引起问题。例如,如果您对 foo
所做的唯一事情就是使用它的 a
属性 而您 return 没有对 foo
做任何事情超出其约束,例如将其传递给接受 A
的其他函数。
但 TypeScript 似乎还没有那么聪明——它没有考虑代码的未来。相反,它在赋值点检查是否所有可能的右侧类型都满足左侧类型的约束。如果不是,它会抛出一个错误。
如果您确定代码不会导致问题(例如,因为您传入的值不只是扩展 A
,它实际上 是 A
) 的实例,然后您可以将值转换为 A 并且赋值将起作用。这是调用外部 API(例如数据库)时的常见模式,它可能 return 未类型化 JSON 您可以将其转换为您知道的类型。像这样:
function alsoWorks1<A extends {a: number}>() {
const foo: A = {a: 1} as A;
console.log (foo);
}
或者您可以决定将其从通用函数更改为非通用函数。像这样:
function alsoWorks2() {
const bar = { a: 1 };
const foo = { a: bar.a }; // no error
console.log (foo);
}
我一直对下面代码中的 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);
}
为什么第一个函数编译失败?我想我误解了一些关于接口和通用约束之间区别的基本知识。
过了一会儿我意识到了这个问题。将 TypeScript 错误 2322 翻译成简单的英语,它的意思是:“你试图设置 A
的值,它有一个数字 属性 a
但它也可能有额外的属性 (!!!),到一个只有数字 属性 a
的对象字面量。因为这个对象字面量缺少其他(潜在的)属性A的,赋值失败。"
为了说明问题,想象一下用真实类型替换 A:
interface A { a: number; b: string; };
const foo: A = { a: 1 }; // compiler error, as expected
如果满足泛型约束 ("has a numeric property a
") 的任何可能类型在泛型类型是特定类型的情况下工作,编译器将抛出错误。
理论上,在这种情况下,TypeScript 可以更智能地检查生成的 foo
是否可能在代码的后面引起问题。例如,如果您对 foo
所做的唯一事情就是使用它的 a
属性 而您 return 没有对 foo
做任何事情超出其约束,例如将其传递给接受 A
的其他函数。
但 TypeScript 似乎还没有那么聪明——它没有考虑代码的未来。相反,它在赋值点检查是否所有可能的右侧类型都满足左侧类型的约束。如果不是,它会抛出一个错误。
如果您确定代码不会导致问题(例如,因为您传入的值不只是扩展 A
,它实际上 是 A
) 的实例,然后您可以将值转换为 A 并且赋值将起作用。这是调用外部 API(例如数据库)时的常见模式,它可能 return 未类型化 JSON 您可以将其转换为您知道的类型。像这样:
function alsoWorks1<A extends {a: number}>() {
const foo: A = {a: 1} as A;
console.log (foo);
}
或者您可以决定将其从通用函数更改为非通用函数。像这样:
function alsoWorks2() {
const bar = { a: 1 };
const foo = { a: bar.a }; // no error
console.log (foo);
}