TypeScript Типобезопасная функция Omit - PullRequest
0 голосов
/ 29 декабря 2018

Я хочу воспроизвести функцию Лодаша _.omit в виде обычного машинописного текста.omit должен вернуть объект с определенными свойствами, удаленными, заданными через параметры, после параметра объекта, который находится на первом месте.

Вот моя лучшая попытка:

function omit<T extends object, K extends keyof T>(obj: T, ...keys: K[]): {[k in Exclude<keyof T, K>]: T[k]} {
    let ret: any = {};
    let key: keyof T;
    for (key in obj) {
        if (!(keys.includes(key))) {
            ret[key] = obj[key];
        }
    }
    return ret;
}

, которая дает мне эту ошибку:

Argument of type 'keyof T' is not assignable to parameter of type 'K'.
  Type 'string | number | symbol' is not assignable to type 'K'.
    Type 'string' is not assignable to type 'K'.ts(2345)
let key: keyof T

Моя интерпретация ошибки такова:

  1. Поскольку ключ - это keyof T, а T - это объект, ключ может быть symbol, number или string.

  2. Поскольку я использую цикл for in, ключ может быть только string, но includes может занять number, если япередать в массив, например?Я думаю.Значит, здесь есть ошибка типа?

Любые идеи о том, почему это не работает и как заставить это работать, приветствуются!

Ответы [ 2 ]

0 голосов
/ 29 декабря 2018
interface Omit {
    <T extends object, K extends [...(keyof T)[]]>
    (obj: T, ...keys: K): {
        [K2 in Exclude<keyof T, K[number]>]: T[K2]
    }
}

const omit: Omit = (obj, ...keys) => {
    let ret = {} as {
        [K in keyof typeof obj]: (typeof obj)[K]
    };
    let key: keyof typeof obj;
    for (key in obj) {
        if (!(keys.includes(key))) {
            ret[key] = obj[key];
        }
    }
    return ret;
}

Для удобства я вытащил большинство набранных текстов в интерфейс.

Проблема заключалась в том, что K (правильное время?) Выводилось как кортеж , а не как объединение ключей.Следовательно, я изменил его ограничение типа соответственно:

[...(keyof T)[]] // which can be broke down to:
keyof T // a union of keys of T
(keyof T)[] // an array containing keys of T
[] // a tuple
[...X] // a tuple that contains an array X

Затем нам нужно преобразовать кортеж K в объединение (для Exclude его из keyof T).Это сделано с K[number], что, я думаю, самоочевидно, это то же самое, что T[keyof T] создание объединения значений T.

Playground

0 голосов
/ 29 декабря 2018

Если мы ограничиваем тип ключей строкой [], это работает.Но это не очень хорошая идея. Ключи должны быть string |номер |символ [];

function omit<T, K extends string>(
  obj: T,
  ...keys: K[]
): { [k in Exclude<keyof T, K>]: T[k] } {
  let ret: any = {};
  Object.keys(obj)
    .filter((key: K) => !keys.includes(key))
    .forEach(key => {
      ret[key] = obj[key];
    });
  return ret;
}
const result = omit({ a: 1, b: 2, c: 3 }, 'a', 'c');
// The compiler inferred result as 
// {
//   b: number;
// }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...