[英]Why does TypeScript not throw an error when the function argument type is mismatched?
[英]Generics typescript, why does this code throw an error Type '{}' cannot be assigned to a type?
我不明白为什么这段代码会抛出错误。 - 类型“{}”不可分配给类型“Keys<T>”。
type Keys<T extends string|symbol>={
[key in T]: string;
};
const foo = <T extends string|symbol>()=>{
const a:Keys<T> = {}
return a
}
此外,如果您手动替换字符串或符号类型,则不会收到任何错误。 只是警告 T 是为函数声明但未使用的。
工作代码示例:
type Keys<T extends string|symbol>={
[key in T]: string;
};
const foo = <T extends string|symbol>()=>{
const a:Keys<string> = {}
return a
}
type Keys<T extends string|symbol>={
[key in T]: string;
};
const foo = <T extends string|symbol>()=>{
const a:Keys<symbol> = {}
return a
}
您可以在此处查看代码
我希望通用代码可以正常工作
因为
const foo = <T = "a" | "b">()=>{
const a: {a: string, b: string} = {} // <- incompatible
return a
}
TLDR:Typescript 对待像string
这样的宽属性类型比像'a' | 'b' | 'c'
这样的属性类型要宽容得多。 'a' | 'b' | 'c'
'a' | 'b' | 'c'
。
首先,您的Keys
类型只是内置的Record
类型,定义为:
type Record<K extends string | number | symbol, T> = { [P in K]: T; }
所以为了简单起见,我将使用它。
那么为什么会这样呢?
function foo<T extends string | symbol>() {
const foo: Record<string, string> = {} // fine
const bar: Record<T, string> = {} // error
}
答案是因为 Typescript 在键类型为无限时与键类型为有限时的行为不同。
string
可以是任何字符串,不跟踪哪个字符串。'a' | 'b' | 'c'
'a' | 'b' | 'c'
是一个有限的字符串列表。Typescript 不会强制执行无限键的存在,因为它不能。 该类型表示任何字符串都会返回一个值,Typescript 允许您这样使用它。
这确实会导致一些问题:
const obj: Record<string, string> = { a: 'test' }
obj.b.toUpperCase() // no type error, crash at runtime
一个更好的类型是:
const obj: Record<string, string | undefined> = { a: 'test' }
obj.b.toUpperCase() // type error
obj.b?.toUpperCase() // fine
这里的值类型可能是undefined
的,这意味着我们必须确保每个属性在我们将其视为string
之前都有一个值。 这给了我们类型安全性。
但是当编译器可以知道键时,它就可以强制执行这些键,并且类型检查变得更加严格:
const obj: Record<'a', string> = { a: 'test' }
obj.b.toUpperCase() // type error
因为它现在有足够的信息来应用更强的类型,所以它确实如此。
那么这里发生了什么:
const foo = <T extends string|symbol>()=>{
const a: Record<T, string> = {} // type error
return a
}
Typescript 是否认为T
可能会被推断为string | symbol
的有限子集? string | symbol
,而不是无限宽的string | symbol
string | symbol
。 所以它应用了更严格的类型检查。
Typescript 是对的。 您的代码根本不分配任何属性,但类型表明这应该有效:
foo<{ a: number }>().a // number
但是您的代码永远不会分配该属性,因此您将在运行时得到undefined
并且可能会导致其他东西崩溃。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.