【问题标题】:Write a typesafe 'pick' function in typescript在打字稿中编写一个类型安全的“pick”函数
【发布时间】:2017-11-10 23:11:08
【问题描述】:

lodash有pick函数,用法如下:

var object = { 'a': 1, 'b': '2', 'c': 3 };

_.pick(object, ['a', 'c']);
// => { 'a': 1, 'c': 3 }

我想用 typescript 写一个类型安全的版本。

这个函数的用法应该是

pick(object, o => o.a, o.b)

目标不是两次指定相同的键,同时保持类型安全。

这有可能实现吗?

【问题讨论】:

  • 您的 pick 函数似乎与 lodash 示例的签名不同?第二个和第三个参数是什么(尤其是第三个)?

标签: typescript lodash


【解决方案1】:

听起来您可能正在寻找Pick type。这样的东西对你有用吗?

function pick<T, K extends keyof T>(obj: T, ...keys: K[]): Pick<T, K> {
  const ret: any = {};
  keys.forEach(key => {
    ret[key] = obj[key];
  })
  return ret;
}

const o = {a: 1, b: '2', c: 3}
const picked = pick(o, 'b', 'c');

picked.a; // not allowed
picked.b  // string
picked.c  // number

【讨论】:

  • 你有什么建议可以去掉这里的任何类型吗?
  • @DanZawadzki 这取决于。这样做的目标是什么?正如所写,any 不会“渗出”实现 - 它只是从无到有构建对象而不会让 Typescript 不开心的最简单方法。
  • 在我的版本中,我决定使用部分函数。项目配置通常不允许使用任何接口,因此我想知道如何在不禁用规则的情况下避免它。 const ret: Partial&lt;Pick&lt;T, K&gt;&gt; = {} 而不是 const ret: any = {};
  • 我看到的唯一负面因素是您还需要将返回类型更改为Partial&lt;Pick&lt;T, K&gt;&gt;。不过,如果这对您可行,听起来是个不错的解决方案。
  • @DanZawadzki 基于unproxify in the typescript handbook 的示例,响应将是const ret = {} as Pick&lt;T, K&gt;
【解决方案2】:

Object.fromEntries(es2019):

function pick<T extends object, K extends keyof T> (base: T, ...keys: K[]): Pick<T, K> {
  const entries = keys.map(key => ([key, base[key]]));
  return Object.fromEntries(entries);
}

【讨论】:

  • 这似乎会导致类型错误,因为Object.fromEntries 的返回类型是ts { [k: string]: T[K]; }
【解决方案3】:

这是我的,使用Object.assign()

function pick<T, K extends keyof T>(object: T, keys: K[]): Pick<T, K> {
  return Object.assign(
    {},
    ...keys.map(key => {
      if (object && Object.prototype.hasOwnProperty.call(object, key)) {
        return { [key]: object[key] };
      }
    })
  );
};

【讨论】:

    【解决方案4】:

    lodash 类型定义使用Pick 来传播道具,因此您不必手动定义它。只需使用npm i --save-dev @types/lodashyarn add -D @types/lodash 安装它们。

    【讨论】:

      【解决方案5】:

      这是我的,扩展@Bayu Karnia 答案:

      function pick<T extends Record<string | number | symbol, T>, K extends keyof T>(
        object: T,
        keys: K[]
      ): Pick<T, K> {
        return Object.assign(
          {},
          ...keys.map((key: K) => {
            return { [key]: object[key] };
          })
        );
      }
      

      【讨论】:

        猜你喜欢
        • 2020-05-28
        • 2016-08-26
        • 2019-12-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-04-27
        • 2017-08-16
        相关资源
        最近更新 更多