在 Typescript 中键入键值对对象并保存对象的键

محم*_*رضا 2 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 }

Run Code Online (Sandbox Code Playgroud)

但它会引发诸如TS2313: Type parameter 'key' has a circular constraint..

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

jca*_*alz 7

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

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

这里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; }'
Run Code Online (Sandbox Code Playgroud)

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

Playground 链接到代码