[英]Generics typescript, why does this code throw an error Type '{}' cannot be assigned to a type?
I can't figure out why this code is throwing an error.我不明白为什么这段代码会抛出错误。 - Type '{}' is not assignable to type 'Keys<T>'.
- 类型“{}”不可分配给类型“Keys<T>”。
type Keys<T extends string|symbol>={
[key in T]: string;
};
const foo = <T extends string|symbol>()=>{
const a:Keys<T> = {}
return a
}
Moreover, if you manually substitute the string or symbol type, no errors will be received.此外,如果您手动替换字符串或符号类型,则不会收到任何错误。 Just a warning that T is declared for a function but not used.
只是警告 T 是为函数声明但未使用的。
Example of working codes:工作代码示例:
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
}
You can check the code here您可以在此处查看代码
I expected generic code to work fine我希望通用代码可以正常工作
Because因为
const foo = <T = "a" | "b">()=>{
const a: {a: string, b: string} = {} // <- incompatible
return a
}
TLDR: Typescript treats wide property types like string
much more leniently than property types like 'a' | 'b' | 'c'
TLDR:Typescript 对待像
string
这样的宽属性类型比像'a' | 'b' | 'c'
这样的属性类型要宽容得多。 'a' | 'b' | 'c'
'a' | 'b' | 'c'
. 'a' | 'b' | 'c'
。
First of all, your Keys
type is just the built in Record
type which is defined as:首先,您的
Keys
类型只是内置的Record
类型,定义为:
type Record<K extends string | number | symbol, T> = { [P in K]: T; }
So I'm going to use that instead for simplicity.所以为了简单起见,我将使用它。
So why is this the case?那么为什么会这样呢?
function foo<T extends string | symbol>() {
const foo: Record<string, string> = {} // fine
const bar: Record<T, string> = {} // error
}
The answer is because Typescript behaves differently when a key type is infinite, versus when the key type is finite.答案是因为 Typescript 在键类型为无限时与键类型为有限时的行为不同。
string
could be any string, which string is not tracked. string
可以是任何字符串,不跟踪哪个字符串。'a' | 'b' | 'c'
'a' | 'b' | 'c'
is a finite list of strings. 'a' | 'b' | 'c'
是一个有限的字符串列表。 Typescript doesn't bother enforcing the existence of infinite keys because it can't. Typescript 不会强制执行无限键的存在,因为它不能。 The type says that any string returns a value, Typescript lets you use it like that.
该类型表示任何字符串都会返回一个值,Typescript 允许您这样使用它。
And this does cause some problems:这确实会导致一些问题:
const obj: Record<string, string> = { a: 'test' }
obj.b.toUpperCase() // no type error, crash at runtime
A better type for that would be:一个更好的类型是:
const obj: Record<string, string | undefined> = { a: 'test' }
obj.b.toUpperCase() // type error
obj.b?.toUpperCase() // fine
Here the value type might be undefined
which means we would have to make sure each property has a value before we treat it as a string
.这里的值类型可能是
undefined
的,这意味着我们必须确保每个属性在我们将其视为string
之前都有一个值。 This gives us type safety back.这给了我们类型安全性。
But when the compiler can know the keys , then it can enforce those keys, and the type checking gets much stricter:但是当编译器可以知道键时,它就可以强制执行这些键,并且类型检查变得更加严格:
const obj: Record<'a', string> = { a: 'test' }
obj.b.toUpperCase() // type error
Since this now has enough information to apply stronger types, it does.因为它现在有足够的信息来应用更强的类型,所以它确实如此。
So what's going here:那么这里发生了什么:
const foo = <T extends string|symbol>()=>{
const a: Record<T, string> = {} // type error
return a
}
Is that Typescript thinks that T
is probably going to be inferred as a finite subset of string | symbol
Typescript 是否认为
T
可能会被推断为string | symbol
的有限子集? string | symbol
, and not the infinite wider type of string | symbol
string | symbol
,而不是无限宽的string | symbol
string | symbol
. string | symbol
。 So it applies the stricter type checking.所以它应用了更严格的类型检查。
And Typescript is right. Typescript 是对的。 Your code does not assign any properties at all, but the types says that this should work:
您的代码根本不分配任何属性,但类型表明这应该有效:
foo<{ a: number }>().a // number
But your code doesn't ever assign that property so you will get undefined
at runtime and that will probably crash something else.但是您的代码永远不会分配该属性,因此您将在运行时得到
undefined
并且可能会导致其他东西崩溃。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.