typescript 过滤对象关键字时的“动态”类型

6ie5vjzr  于 2022-12-01  发布在  TypeScript
关注(0)|答案(2)|浏览(152)

假设我有以下有效负载:
{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.必须键入
1.只想键入与我们的用例相关的键
1.按照TS最佳做法执行

63lcw9qa

63lcw9qa1#

如果你不需要对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>正是您需要的类型:K是扩展keyof T的任意类型。假设您将常量参数传递给此函数,您将得到一个文本类型的并集,如"a" | "b"K
我不知道有什么方法可以让Object.fromEntries进行类型检查,除了像我们上面所做的那样通过any进行强制转换。根据我的经验,当你开始在Object原型上弄乱函数时,你必须稍微引导Typescript来获得正确的类型。

jgovgodb

jgovgodb2#

Silvio的答案与我在评论中发布的调整一起工作,但是如果你想依赖于_.pick的话,看起来Lodash支持这一点。
https://lodash.com/docs/4.17.15#pick
它完全按照你(和我!)想要的方式工作。

相关问题