首页 > 解决方案 > 过滤对象键时的“动态”类型

问题描述

假设我有以下有效负载:

{a: 1, b: 2, c: 3}

我想要一个函数,给定一个对象,选择一些键并相应地返回一个类型。

function pick<T>(obj: any, ...keys: string[]): T {
  return (
    Object.fromEntries(
      keys
        .filter(key => key in obj)
        .map(key => [key, obj[key]])
    )
  ) as T;
}

const test = { a: 1, b: 2, c: 3 };

type Foo = {
  a: number,
  b: number
}
const result = pick<Foo>(test, 'a', 'b');
console.log(result);

有没有办法更好地处理这个问题?我知道使用类型强制几乎是关闭 Typescript 安全网。

例如,如果我这样做:

console.log(pick<Foo>(test, 'b'));

我告诉 typescript 函数 pick 返回一个 Foo 对象,但它没有a定义键。

用例是我们有 API 调用,我们:

  1. 必须打字
  2. 只想为我们的用例键入相关键
  3. 遵循 TS 最佳实践

标签: typescriptapi

解决方案


如果您对不进行类型检查的实现感到满意pick,那么您至少可以使类型全部对齐。我们将为此使用的超级方便的 Typescript 类型实际上称为Pick.

function pick<T, K extends keyof T>(obj: T, ...keys: K[]): Pick<T, K> {
  return (
    Object.fromEntries(
      keys
        .filter(key => key in obj)
        .map(key => [key, obj[key]])
    )
  ) as any;
}

函数实现是完全相同的,除了最后我们通过 进行any转换,这有效地告诉 Typescript 信任我们。Pick<T, K>正是你想要的类型:它说“取 type T,用 type 下标K,看看我们得到了什么”。K是扩展的任意类型keyof T。假设你将常量参数传递给这个函数,你会得到一个类似"a" | "b"for的文字类型的联合K

我不知道有一种方法可以进行类型检查,而不是像我们上面所做的那样Object.fromEntries进行强制转换。any以我的经验,当你开始弄乱Object原型上的函数时,你必须稍微哄一下 Typescript 才能得到正确的类型。


推荐阅读