声明任意嵌套的数组(递归类型定义)

时间:2018-12-06 07:12:05

标签: typescript tsc typescript3.0

说我有一个类似的功能:

const nested = function(v: string | Array<string> | Array<Array<string>>){...}

问题是v可能嵌套了5或6层深度。如何声明一个任意嵌套的类型?

例如,我该如何处理:

nested([['zam'],[[[['zimm']]]]])

2 个答案:

答案 0 :(得分:1)

您可以很容易地描述一个任意嵌套的数组类型,如下所示:

interface NestedArray<T> extends Array<T | NestedArray<T>> { }

允许使用这种类型的递归引用(不允许使用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

但是编译器放弃了在五层深度之后检查此类嵌套类型的方法:

// no error!  
const what: NestedArray<number> = [[[[["a"]]]]]; // 

此外,给定数组类型,您不能轻易推断出最终元素类型。例如:

declare function doesntWork<T>(arr: NestedArray<T>): T;
const t = doesntWork([[1,2,3]]) ; // T is number[] | ConcatArray<number[]>; 

您可能希望将T推断为number,但是编译器没有义务这样做,因为[[1,2,3]]既是NestedArray<number[]>又是{{ 1}}。即使您尝试强制NestedArray<number>仅接受不是数组的NestedArray<T>,编译器也不会按照您想要的方式来推断元素类型。

如果您需要推断嵌套元素的类型,您会发现自己想要创建一个递归T别名,可能涉及conditional types。但是您不能在TypeScript中做到这一点(无论如何从3.2版本开始)。

type

您能做的最好的事情就是选择一个深度来支持(例如10个级别),然后展开递归类型别名:

type NestedElementType<T> = T extends Array<infer A> ? NestedElementType<A> : T; // error 

那将起作用:

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

鉴于所有这些警告,您可以使用此类型:

declare function doesWork<N extends NestedArray<any>>(arr: N): NestedElementType<N>;
const w = doesWork([[1,2,[3],[[4]]]]) ; // returns number 

是否值得取决于您。希望能有所帮助;祝你好运!

答案 1 :(得分:0)

这种方式工作:

    type NestedArray<T> = T | NestedArray<T>[];
    const arr: NestedArray<string> = [[[["zimm"]]]];