“pick”函数的 TypeScript 通用类型(结果对象值类型)

Del*_*avo 4 javascript types generic-type-argument typescript

在编写 pick 函数的类型时遇到问题。当仅选择一个键或具有相同类型值的多个键时,一切正常。但是,如果我尝试选择几个键并且它们的值是不同类型 - 我会收到错误。不太确定我在哪里犯了错误。

感谢您的时间。

export interface Mapper<T = any, R = any> {
  (arg: T): R;
}


export function pick<O, T extends keyof O>(keys: T[], obj?: O): { [K in T]: O[T] };

export function pick<T>(keys: T[], obj?: never): Mapper;

export function pick<O, T extends keyof O>(keys: T[], obj?: O) {
  const picker: Mapper<O, { [K in T]: O[T] }> = _obj =>
    keys.reduce((acc, key) => {
      if (key in _obj) {
        acc[key] = _obj[key];
      }
      return acc;
    }, {} as O);

  return obj ? picker(obj) : picker;
}

const obj = { someKey: 'value', otherKey: 42, moreKey: ['array value'] };

const newObj = pick(['otherKey'], obj);
//OK. TS type for newObj is {otherKey: number}

const n: number = newObj.otherKey;
// OK

const otherNewObj = pick(['otherKey', 'someKey'], obj);
//no really OK. TS type for otherNewObj is {otherKey: number | string, someKey: number | string}

const m: number = otherNewObj.someKey;
// Error. Type string | number is not assignable to the number
Run Code Online (Sandbox Code Playgroud)

Tit*_*mir 5

您可能想要使用的映射类型存在错误,O[K]因此O[T]您最终会得到{ [K in T]: O[K] }. 您需要每个 key 的类型K,而不是联合中所有属性的类型T

我还会使用Picksince是同态的并且会保留诸如andPick之类的修饰符。readonlyoptional

obj?: never可能没有做你想要它做的事情,任何东西都可以分配给never,你最好省略该重载中的参数:

export function pick<O, T extends keyof O>(keys: T[], obj?: O): Pick<O, T>;
export function pick<T>(keys: T[]): Mapper;
export function pick<O, T extends keyof O>(keys: T[], obj?: O) {
    //....
}
Run Code Online (Sandbox Code Playgroud)

游乐场链接