我在程序中构建了一个通用函数,它接受
Type
数组。在某些情况下,Type
可能是 Date
,有时可能是其他东西。
function processArray<Type>(arr: Type[]) {
if (arr instanceof Array<Date>) { // error
arr.map(x => x.getFullYear());
}
}
我怎么能猜出类型呢?检查数组的
typeof
或 instanceof
不起作用。我有一个将类型存储在属性中的想法,但我认为应该有比创建属性并存储类型更好的方法。
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()]);
但是你在运行时做了更多的工作。如果它是一个大数组,您将检查每个元素。