首页 > 解决方案 > 如何将对象键的值映射到 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

标签: typescripttypescript-typings

解决方案


您可以使用以下内容:

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>;
}

打字稿游乐场

编辑:上面的解决方案有两个问题:

  1. 生成的对象具有任意键string(含义obj.nonExistingKey.qux将通过)
  2. 尽管提供的数组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 的方法。如果它对你来说真的很重要,你可以实现一些类型保护


推荐阅读