typescript - 如何将对象键的值映射到 TypeScript 中的同一对象?
问题描述
如何以 IntelliSense 知道的工作方式将对象键的值映射到 TypeScript 中的同一对象,如下例所示?
const obj = getByName([
{ __name: 'foo', baz: 'foobar' },
{ __name: 'bar', qux: 'quux' },
]);
obj.foo.__name // ok
obj.foo.baz // ok
obj.foo.quuz // not ok
obj.bar.__name // ok
obj.bar.qux // ok
obj.bar.quuz // not ok
解决方案
您可以使用以下内容:
export function getByName<
TName extends string,
TObj extends {__name: TName},
>(arr: TObj[]): Record<TName, TObj> {
return arr.reduce((acc, obj) => {
return {
...acc,
[obj.__name]: obj,
};
}, {} as Partial<Record<TName, TObj>>) as Record<TName, TObj>;
}
编辑:上面的解决方案有两个问题:
- 生成的对象具有任意键
string
(含义obj.nonExistingKey.qux
将通过) - 尽管提供的数组
obj.foo.qux
中没有,但它认为没问题。{__name: 'foo', qux: 'value'}
要解决问题 no1,我们可以传递数组as const
:
function getByName<TObj extends {__name: string}>(arr: readonly TObj[]) {
return arr.reduce((acc, obj) => {
return {
...acc,
[obj.__name]: obj,
};
}, {}) as Record<TObj['__name'], TObj>;
}
const obj = getByName([
{ __name: 'foo', baz: 'foobar' },
{ __name: 'bar', qux: 'quux' },
] as const);
obj.nonExistingKey.quuz // not ok NOW!
但是,我不知道使用泛型解决问题 2 的方法。如果它对你来说真的很重要,你可以实现一些类型保护。