首页 > 解决方案 > 在 Typescript 中键入键值对对象并保存对象的键

问题描述

我在以下示例中有键值对对象


interface ItemType {
    a: number;
    b: string;
}

const list = {
    first: {a: 1, b: 'one'},
    second: {a: 2, b: 'two'},
    third: {a: 3, b: 'three'},
} as { [key in keyof typeof list]: ItemType }

但它会引发错误,例如TS2313: Type parameter 'key' has a circular constraint..

我希望所有项目的类型为ItemType,但仍希望列表保存我插入的键。如果我将其转换为{ [key in string]: ItemType },我将丢失列表的键名。:(

标签: typescript

解决方案


如果您想验证一个值是否可分配给一个类型,而不是将其扩大到该类型并可能丢弃您关心的信息,您可以使用辅助标识函数,如下所示:

const itemDict = <K extends PropertyKey>(dict: { [P in K]: ItemType }) => dict;

这里itemDict()应该只接受你正在寻找的类型的对象作为参数:它的键是任何类似键的东西K extends PropertyKey,当你调用它时编译器会推断它,并且它的属性是ItemTypes。因为键集K, 是类型的一部分,所以不会被遗忘:

const list = itemDict({
  first: { a: 1, b: 'one' },
  second: { a: 2, b: 'two' },
  third: { a: 3, b: 'three' },
});

list.second.a.toFixed(); // okay

list.fourth; // error!
// Property 'fourth' does not exist on type 
// '{ first: ItemType; second: ItemType; third: ItemType; }'

请注意,list编译器根据需要推断为 type {first: ItemType, second: ItemType, third: ItemType}

Playground 代码链接


推荐阅读