4 typescript tsc typescript3.0
假设我有一个类似的函数:
const nested = function(v: string | Array<string> | Array<Array<string>>){...}
Run Code Online (Sandbox Code Playgroud)
问题是v可能嵌套 5 或 6 层深。如何声明任意嵌套的类型?
例如,我该如何处理:
nested([['zam'],[[[['zimm']]]]])
Run Code Online (Sandbox Code Playgroud)
您可以相当容易地描述任意嵌套的数组类型,如下所示:
interface NestedArray<T> extends Array<T | NestedArray<T>> { }
Run Code Online (Sandbox Code Playgroud)
允许这种类型的递归引用(而别名则type不允许),因为接口的基本类型的计算是deferred 的。
不幸的是,使用它并不简单。您可以创建此类类型的值:
// works as expected
const nums: NestedArray<number> = [1,[2,[3,[4,[5],6,[7]],[8]],[[9]]]];
// errors as expected
const oops: NestedArray<number> = [1,[2,["3",[4,[5],6,[7]],[8]],[[9]]]]; // error
Run Code Online (Sandbox Code Playgroud)
但编译器在大约五层深度之后放弃检查此类嵌套类型:
// no error!
const what: NestedArray<number> = [[[[["a"]]]]]; //
Run Code Online (Sandbox Code Playgroud)
此外,您无法轻松推断出给定数组类型的最终元素类型。例如:
declare function doesntWork<T>(arr: NestedArray<T>): T;
const t = doesntWork([[1,2,3]]) ; // T is number[] | ConcatArray<number[]>;
Run Code Online (Sandbox Code Playgroud)
您可能期望T被推断为number,但编译器没有义务这样做,因为[[1,2,3]]是 aNestedArray<number[]>和 a NestedArray<number>。即使您尝试强制NestedArray<T>只接受T不是数组的 a,编译器也不会按照您想要的方式推断元素类型。
如果您需要推断嵌套元素类型,您会发现自己想要创建一个递归type别名,可能涉及条件类型。但你不能在 TypeScript 中做到这一点(无论如何从 3.2 开始)。
type NestedElementType<T> = T extends Array<infer A> ? NestedElementType<A> : T; // error
Run Code Online (Sandbox Code Playgroud)
您能做的最好的事情就是选择支持的深度(例如 10 个级别),然后展开递归类型别名:
type NestedElementType<T> = T extends Array<infer A> ? NET1<A> : T;
type NET1<T> = T extends Array<infer A> ? NET2<A> : T;
type NET2<T> = T extends Array<infer A> ? NET3<A> : T;
type NET3<T> = T extends Array<infer A> ? NET4<A> : T;
type NET4<T> = T extends Array<infer A> ? NET5<A> : T;
type NET5<T> = T extends Array<infer A> ? NET6<A> : T;
type NET6<T> = T extends Array<infer A> ? NET7<A> : T;
type NET7<T> = T extends Array<infer A> ? NET8<A> : T;
type NET8<T> = T extends Array<infer A> ? NET9<A> : T;
type NET9<T> = T extends Array<infer A> ? NETX<A> : T;
type NETX<T> = T extends Array<infer A> ? unknown : T; // bail out
Run Code Online (Sandbox Code Playgroud)
那可行:
declare function doesWork<N extends NestedArray<any>>(arr: N): NestedElementType<N>;
const w = doesWork([[1,2,[3],[[4]]]]) ; // returns number
Run Code Online (Sandbox Code Playgroud)
考虑到所有这些警告,您可以使用这种类型:
function flatten<N extends NestedArray<any>>(arr: N): Array<NestedElementType<N>> {
const ret: Array<NestedElementType<N>> = [];
arr.forEach(l => {
if (Array.isArray(l)) {
ret.push(...flatten(l));
} else {
ret.push(l);
}
});
return ret;
}
const flattened = flatten([["a"], ["b"], [[[[["c"]]], "d"]]]); // string[]
Run Code Online (Sandbox Code Playgroud)
这取决于你是否值得。希望有帮助;祝你好运!
| 归档时间: |
|
| 查看次数: |
857 次 |
| 最近记录: |