【问题标题】:TypeScript generic type for "pick" function (result object values types)“pick”函数的 TypeScript 泛型类型(结果对象值类型)
【发布时间】:2020-05-13 00:52:23
【问题描述】:

选择功能的书写类型有问题。当只选择一个键或几个具有相同类型值的键时,一切正常。但是如果我试图选择几个键并且它们的值是不同的类型 - 我会得到一个错误。不太清楚我在哪里做错了。

感谢您的宝贵时间。

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

【问题讨论】:

    标签: javascript typescript types generic-type-argument


    【解决方案1】:

    您的映射类型有一个错误,您可能想使用O[K] 而不是O[T],所以您最终会使用{ [K in T]: O[K] }。您需要每个键 K 的类型,而不是 T 联合中所有属性的类型。

    我也会使用Pick,因为Pick 是同态的,并且会保留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) {
        //....
    }
    

    Playground Link

    【讨论】:

    • 非常感谢,完美解答!我只是没有考虑在这种情况下使用pick。我也可以问你这个重载的一般情况,有没有办法在没有重载但有条件类型的情况下编写相同的类型?
    猜你喜欢
    • 2018-07-03
    • 2019-05-30
    • 2021-12-06
    • 1970-01-01
    • 2021-04-10
    • 2020-11-15
    • 1970-01-01
    • 2019-05-06
    • 2016-09-06
    相关资源
    最近更新 更多