【问题标题】:Types for a function that receives an object of type `[key: string]: SOME_TYPE` and returns an array of type `SOME_TYPE[]`接收“[key: string]: SOME_TYPE”类型对象并返回“SOME_TYPE[]”类型数组的函数的类型
【发布时间】:2020-12-10 18:13:37
【问题描述】:

我有一些包含数据库文档的对象,我经常需要将它们转换为数组。

例子:

const MY_OBJECT = {
  docId_1: {...doc1},
  docId_2: {...doc2},
  docId_3: {...doc3},
  // AND SO ON
}

我需要将它转换成这样的数组:

const MY_ARRAY_FROM_OBJECT = [
  {...doc1}, 
  {...doc2}, 
  {...doc3},
  // AND SO ON...
]

这是我用来进行转换的代码:

function buildArrayFromObject(obj) {
  const keys = Object.keys(obj);
  const arr = [];
  for (const key of keys) {
    arr.push(obj[key]);
  }
  return arr;
}

我需要键入该函数,以便可以将它与具有以下类型的对象一起使用:

interface BLOGPOSTS_ALL {
  [key: string]: BLOGPOST
}

interface PRODUCTS_ALL {
  [key: string]: PRODUCT
}

所以当我用每个不同的对象调用它们时,我希望 Typescript 知道返回的数组类型是什么。

例如:

const BLOGPOSTS_ALL_ARRAY = buildArrayFromObject(BLOGPOSTS_ALL);  // SHOULD BE "BLOGPOST[]"
const PRODUCTS_ALL_ARRAY = buildArrayFromObject(PRODUCTS_ALL);    // SHOULD BE "PRODUCT[]"

这是我尝试过的:

function buildArrayFromObject<T, K extends keyof T>(obj: T): T[K][] {
  const keys = Object.keys(obj);
  const arr = [];
  for (const key of keys) {
    arr.push(obj[key]);
  }
  return arr;
}

但我收到此错误:

Typescript 将函数的返回类型评估为类型never[]

【问题讨论】:

  • 首先,有没有什么限制你使用Object.values(..)这个功能?
  • @r3dst0rm 没问题。我可以用那个。我只是习惯了Object.keys()
  • 其实IE不支持Object.values(),所以我宁愿用Object.keys()
  • 如另一条评论所述,您可以将 Object.keys 的返回值转换为以下内容:const keys = Object.keys(obj) as K[];,一切顺利。

标签: arrays typescript function object typescript-typings


【解决方案1】:

你可以做的是:

创建一个抽象类型来定义您的数据库处理的样子:

// Create an Entity type to define how your database objects look like
type Entities<T> = { [key: string]: T | undefined }

因此,您可以这样表达您的产品和博文:

type BLOGPOSTS = Entities<BLOGPOST>;
type PRODUCTS = Entities<PRODUCT>;

为了以类型安全的方式将它们转换为数组,您可以使用 JavaScript API 提供的 Object.values 方法 - 有关详细信息,请参阅 MDN

可以将buildArrayFromObject 方法替换成这样的:

const isNil = <T>(a: T | null | undefined): a is null | undefined => a === null || a === undefined;
const isAssigned = <T>(a: T | null | undefined): a is T => !isNil(a);
const entitiesToArray = <T>(entity: Entities<T>): T[] => Object.values(entity).filter(isAssigned);

此方法使用Object.values 方法将对象转换为数组。之后它被过滤以包含一个没有未定义值的数组。因此我使用了两个辅助方法isAssignedisNil。请参阅此 CodeSandbox 示例:Code SandBox

基于您的担忧,IE11 不支持 Object.value 方法,您可以为该方法添加一个 polyfill。通过粘贴 polyfill 或使用 npm 将其添加到项目中。 或者,您可以将此代码替换为以下答案Use Object.keys to mimick Object.values

【讨论】:

  • 非常感谢您的回答。我正在寻找一种更简单的方法来解决这个问题。如果我决定只将此函数用于这两种对象类型怎么办:BLOGPOSTS_ALLPRODUCTS_ALL。所以我不必使函数“太”通用。有没有办法简化这个?
  • 其实有。如果对您没有问题,您可以像这样在您的解决方案中转换Object.keys 的返回值:const keys = Object.keys(obj) as K[]; 然后问题就神奇地消失了,我的回答将是一个很好的附录。让我知道它是否有帮助
猜你喜欢
  • 1970-01-01
  • 2021-12-15
  • 1970-01-01
  • 2021-08-13
  • 1970-01-01
  • 2020-12-09
  • 2020-08-20
  • 2020-06-13
相关资源
最近更新 更多