TypeScript generi c type для функции "pick" (типы значений объекта результата) - PullRequest
1 голос
/ 27 января 2020

Есть проблемы с типом записи для функции выбора. Все работает нормально, выбирая только один ключ или несколько ключей со значениями одного типа. Но если я попытаюсь выбрать несколько ключей и их значения разных типов - я получу ошибку. Не совсем уверен, где я допустил ошибку.

Спасибо за ваше время.

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

1 Ответ

1 голос
/ 27 января 2020

В вашем отображаемом типе есть ошибка, которую вы, вероятно, хотите использовать O[K] вместо O[T], поэтому вы получите { [K in T]: O[K] }. Вам нужен тип для каждого ключа K, а не тип всех свойств в объединении T.

Также я бы использовал Pick, поскольку Pick является homomorphi c и сохранит модификаторы такие как readonly и optional.

Кроме того, 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) {
    //....
}

Playground Link

...