泛型变量的打字稿 typeof

问题描述 投票:0回答:1

我在程序中构建了一个通用函数,它接受

Type
数组。在某些情况下,
Type
可能是
Date
,有时可能是其他东西。

function processArray<Type>(arr: Type[]) {
  if (arr instanceof Array<Date>) { // error
    arr.map(x => x.getFullYear());
  }
}

我怎么能猜出类型呢?检查数组的

typeof
instanceof
不起作用。我有一个将类型存储在属性中的想法,但我认为应该有比创建属性并存储类型更好的方法。

typescript
1个回答
0
投票
当 TypeScript 编译为 JavaScript 时,

TypeScript 的类型系统,包括 generic 类型参数将被 erased。没有可供查看的运行时类型信息。 你不能写像

arr instanceof Array<Date>
这样的东西,因为这只是运行时的
arr instanceof Date
,而且无论如何它总是正确的。您应该考虑在运行时需要看到什么,然后编写代码。


正如您所提到的,您可以添加一些对元素类型进行编码的数据,例如

type
属性,并接受可接受类型的 union

type MyData =
  { type: "Date", array: Date[] } |
  { type: "string", array: string[] } | 
  // other specific cases you want to handle...
  { type: "unknown", array: unknown[] }

function processArray(data: MyData) {
  if (data.type === "Date") {
    data.array.map(x => x.getFullYear());
  }
}

这可行,但它要求您实际传递额外的数据:

processArray({ type: "Date", array: [new Date()] });

并且该函数实际上不再需要通用,因为您可以处理的案例列表是有限的,并且您让所有其他案例都是“未知”。 不过,如果必须的话,您仍然可以使用泛型:

function processArray<T>(data: MyData & { array: T[] }) {
  if (data.type === "Date") {
    data.array.map(x => x.getFullYear());
  }
}

如果您不想更改数据,那么您唯一的选择是对数组执行某种运行时测试。唯一安全的方法是检查数组的每个元素(因为通用数组可以保存异构数据,例如

["a", new Date(), 123]
),然后仅在每个元素都属于预期类型时才采取行动:

function processArray<T>(arr: T[]) {
  if (arr.every(x => x instanceof Date)) {
    arr.map(x => x.getFullYear());
  }
}

这依赖于 TypeScript 将 every()

 数组方法
视为 类型保护函数 的事实,如果它返回 true
,它会缩小数组元素类型。

这很容易调用,因为您不需要添加任何新数据:

processArray([new Date()]);
但是你在运行时做了更多的工作。如果它是一个大数组,您将检查每个元素。


由您决定采用哪种一般方法:保留数据结构但执行广泛的运行时测试,或更改数据结构。不管怎样,你需要自己做这些事情,因为 TypeScript 类型系统在运行时不存在。

Playground 代码链接

© www.soinside.com 2019 - 2024. All rights reserved.