我在使用 TypeScript 输入对象时遇到问题
我声明了应用程序的某些文件使用的类型:
type Category = "cat1"|"cat2"|"cat3"|"cat4"
Run Code Online (Sandbox Code Playgroud)
我用来Category输入一个对象并且一切正常使用:
const obj: {
[key in Category]: string
} = {---}
Run Code Online (Sandbox Code Playgroud)
但现在,我想添加 2 个不是Category对象值的键。我认为通过输入这样的对象会很容易:
const obj: {
customKey1: string
customKey2: string
[key in Category]: string
} = {---}
Run Code Online (Sandbox Code Playgroud)
但 TS 没有按预期工作,而是发送了 3 个错误:TS2464、TS1170 和 TS2693
A computed property name must be of type 'string', 'number', 'symbol' or 'any'. ts(2464)
'Category' only refers to a type, but is using as a value here. ts(2693)
A computed property name in a type template must refer to an expression whose type is a literal type or a 'unique symbol' type. ts(1170)
Run Code Online (Sandbox Code Playgroud)
好吧...为什么?由于Category通过文件共享,我不想通过添加仅在此处需要的这些自定义密钥来编辑它。我解决了这个问题,所以如果其他人面临这个问题,我会在下面给出解决方案,但是有人知道为什么我的第一个想法不能应用吗?
我不明白为什么[key in Category]: string单独写入可以工作,但如果添加另一个键则会抛出错误。
jca*_*alz 19
语法{[K in XXX]: YYY}是映射类型,一种特殊的对象类型,它迭代类似键类型表达式的联合成员,并为类型表达式中的每个成员XXX使用类型参数。(注意,代表类型,而不是属性键值,因此按照惯例,我们在那里使用大写字符)。您可以在表达式内部使用,以便每个键可以具有不同的值类型,就像相当于。 映射类型语法不可概括或扩展;您不能将其他属性放入其中,例如 ,也不能将它们放入声明中,或对其执行任何其他操作。这样做是一个语法错误。从某种意义上说,大括号是映射类型语法的一部分,尽管它们看起来像其他对象类型中的大括号,但它们的作用却不同。KYYYKKYYYKXXX{[K in "a" | "b"]: K}{a: "a", b: "b"}{[K in XXX]: YYY; somethingElse: string}interface{ ... }
重要的是不要将此语法与类似的索引签名{[k: XXX]: YYY}语法混淆。映射类型使用关键字,而索引签名则不使用。索引签名需要一个虚拟密钥名称标识符(在此示例中),它不是类型参数。虚拟键名称仅存在于键内部,不能在表达式中使用,因此它不允许您为 ; 中的不同键分配不同的值。索引签名不会以任何方式迭代内部的键。作为签名,索引签名可以与其他属性一起在任何对象类型中使用,例如,只要其他属性不与索引签名冲突。它们可以包含在声明中。大括号不是索引签名语法的一部分。inkYYYXXXXXX{[k: XXX]: YYY; somethingElse: string}interface
因此,您的问题是:为什么不能向映射类型添加其他属性?为什么映射类型中的花括号不像其他对象类型中那样工作?
microsoft/TypeScript#13573上有一个问题提出了这个确切的问题。不过,似乎还没有明确的答案。这似乎是一个意想不到的用例。有一段时间,作为统一映射类型和索引签名的一部分,microsoft/TypeScript#26797上的拉取请求可能会合并到该语言中,但这从未发生过。TS 团队成员在microsoft/TypeScript#45089中的相关评论解释说,此时这里不太可能发生任何更改,因为它提出了有关如何处理可能冲突的类型和泛型的问题:
混合映射类型和属性声明会产生奇怪的影响,可以通过交集优雅地解决
我不会在这里明确讨论这些;您可以查看链接的问题以获取更多信息。
就目前而言,这就是“为什么会这样”的答案。那么你能做什么呢?上面的评论提到了交叉点;您可以通过交集将两个对象类型的属性合并在一起,因此{a: string} & {b: string}本质上与 相同{a: string; b: string}。因此编写对象类型的一种方法是:
type MyObjType =
{ [K in Category]: string } &
{ customKey1: string, customKey2: string };
Run Code Online (Sandbox Code Playgroud)
您不能直接使用交集作为接口类型,但允许您使用静态已知的键使接口扩展其他命名类型。您具有静态已知的键,因为不是通用的,但它不是命名类型。您可以自己命名然后扩展它:{[K in Category]: string}Category
type CategoryProps = { [K in Category]: string };
interface MyObjType extends CategoryProps {
customKey1: string
customKey2: string
}
Run Code Online (Sandbox Code Playgroud)
或者,您可以使用实用程序Record<K, V>类型并扩展它,而无需声明新名称:
interface MyObjType extends Record<Category, string> {
customKey1: string
customKey2: string
}
Run Code Online (Sandbox Code Playgroud)
最后,您始终可以走另一个方向,为所有键使用映射类型,而不是尝试单独添加它们:
type MyObjType =
{ [K in Category | "customKey1" | "customKey2"]: string };
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
2820 次 |
| 最近记录: |