如何用打字稿表示嵌套数组

Ale*_*lls 4 tsc typescript3.0

假设我有一个字符串数组,例如:

const a = ['foo', ['aa'], [['zzz',['bar']]]];

export const acceptsArray = (v: Array<any>) : string => {
   returns flattenDeep(v).join(' ');
};
Run Code Online (Sandbox Code Playgroud)

除了使用Array<any>如何表示嵌套的字符串数组?

小智 7

请检查我之前写的这个实用函数。

// NestedArray<T> represents T or Array of T or Array of Array of T .....
// let nestedNumbers: NestedArray<number> = [[[[[1]]]]];
export type NestedArray<T> = Array<T> | Array<NestedArray<T>>;

// Able to flatten deeply nested array
// flattenArray(nestedNumbers) should produce => [1] : Array<number>
export const flattenArray = <T>(arr: NestedArray<T>): Array<T> => {
  if (!Array.isArray(arr)) return arr ? [arr] : [];

  return arr.reduce<Array<T>>((acc: Array<T>, item: NestedArray<T>) => {
    if (Array.isArray(item)) {
      return [...acc, ...flattenArray(item)];
    }
    return [...acc, item];
  }, []);
}
Run Code Online (Sandbox Code Playgroud)

  • 如果它始终是一个数组,似乎这会更准确?`导出类型 NestedArray&lt;T&gt; = Array&lt;T&gt; | Array&lt;NestedArray&lt;T&gt;&gt;;`,因为这里 T 本身不必是数组。 (2认同)

Fla*_*nte 6

简答

新功能仅适用于 Typescript 3.7+

type A = 'foo' | 'aa' | 'zzz' | 'bar' | A[]

const a:A = ['foo', ['aa'], [['zzz',['bar']]]];

export const acceptsArray = (v: Array<A>) : string => {
   returns flattenDeep(v).join(' ');
};
Run Code Online (Sandbox Code Playgroud)

完整答案

需要注意的是,原始作者代码的意图存在歧义。上面的简短回答是一种输入方式,下面是另一种,两者都是有效的输入方式。只有作者才能决定他的真正意图。波纹管打字更严格

打字的优点是记录程序员的意图。但是由于作者问题没有类型,我无法确切地推断出他的意思。

// When autor say this:
const a = ['foo', ['aa'], [['zzz',['bar']]]];

// Should he mean this:
type A0 = 'foo' | 'aa' | 'zzz' | 'bar' | A[]

// or this:
type A1 = string | string[] | (string | string[])[][] 

// Both types 'A0' and 'A1' are valid types for variable 'a', 
// but type 'A1' is strictier.
Run Code Online (Sandbox Code Playgroud)

原答案

注意:当 TS 3.5 是最后一个版本时,我写了下面的答案。上面提到了必要的重要更新。波纹管答案仍然有效。如果可能,我将重构答案以使其更短。

一种更严格的方法来解决您的问题:

type A = string | string[] | (string | string[])[][]

const a:A = ['foo', ['aa'], [ ['zzz',['bar'] ] ] ];

export const acceptsArray = (v: Array<A>) : string => {
   returns flattenDeep(v).join(' ');
};
Run Code Online (Sandbox Code Playgroud)

一般问题

上面的答案有效,但让我们解决您可能更通用的问题:

如何表示任意类型的任意级别的嵌套数组?

嵌套:表示

首先,任何数组都有一个类型。这是一个字符串数组:

type A = Array<string> // type definition
const a: A = ['a','b','c'] //instance
Run Code Online (Sandbox Code Playgroud)

下面我们更进一步,在一个 Array 中引入另一个 Array。具体来说,我们有一个“字符串数组”数组,仅此而已

type A = Array<string>
type B = Array<A>
// Ok ! 
const b0: B = [['a','b','c'],['foobar'],['1','2','3','4','5']] //ok
const b1: B = [['1','2','3']] //ok

//Attention !!!
const b2: B = ['1','2','3'] //error! Array<string> is not equal to Array<Array<string>>
const b3: B = [[1,2,3]] // error! Array<Array<number>> is not equal to Array<Array<string>>
Run Code Online (Sandbox Code Playgroud)

B上面的类型可以这样写:type B = Array<Array<string>>. 在打字稿中,如果你想要一个“字符串数组数组”,你也可以这样表示:

最短表示

type X0 = Array<Array<string>>
type X1 = string[][]  // short form!
Run Code Online (Sandbox Code Playgroud)

同样,如果你想要一个“字符串数组的数组”,你可以这样做:

type Y0 = Array<Array<Array<string>>>
type Y1 = string[][][] // short form!

// this also works!!
type Y2 = (string | number)[][][]
Run Code Online (Sandbox Code Playgroud)

等等...

嵌套:类型检查

重要的是要理解 Typescript 对于您指定为数组类型的内容是严格的。例如:

// Given this types...
type A = string
type B = Array<string>
type Both = A | B

// and this instances...
const a:A = 'foo'
const b:B = ['foo']

// so...

const r0: Array<A> = [a,a] //ok
const r1: Array<B> = [a,a] //error: string is not of type Array<string>
const r2: Array<B> = [b,b] //ok
const r3: Array<Both> = [a,b] //ok


Run Code Online (Sandbox Code Playgroud)

嵌套:通用性

如果我们想要一个 type 的数组怎么办T, whereT任何 特定类型。

// Some specific types
type SPECIFIC_TYPE_01 = string
type SPECIFIC_TYPE_02 = number
type SPECIFIC_TYPE_03 = //...etc

// A generic array of any specific type
type GenericArray<T> = Array<T>

// use:
const a: GenericArray<SPECIFIC_TYPE_01> = ['a','b','c'] //ok
const b: GenericArray<SPECIFIC_TYPE_02> = [1,2,3] //ok

Run Code Online (Sandbox Code Playgroud)

注:显然不是使用这些长名字,你可能只是用Array<string>Array<number>等我只是beeing说教显示泛型如何与阵列。


加起来

波纹管我使用以上知识来解决您的原始问题。

// Given...
type NestedArray0<T> = T[] //same as Array<T>
type NestedArray1<T> = T[][] //same as Array<Array<T>>
type NestedArray2<T> = T[][][] // same as Array<Array<Array<T>>>
type NestedArray3<T> = T[][][][]  // etc you get the point...

// So you can do things like...
const a0: NestedArray0<number> = [1,2,3]  //ok
const a1: NestedArray1<number> = [[1,2,3]]   //ok
const a2: NestedArray2<number> = [[[1,2,3]]]   //ok
const a3: NestedArray3<number> = [[[[1,2,3]]]]  //ok

// The type of your examples (based in what you informed) is...
type MyType = 
    | string  // 'foo'
    | NestedArray0<string> // ['aa']
    | NestedArray1<string | string[]> //  [['zzz',['bar']]]

const a: Array<MyType> = ['foo', ['aa'], [['zzz',['bar']]] ]; //ok

// so you can do

export const acceptsArray = (v: Array<MyType>) : string => {
   returns flattenDeep(v).join(' ');
};

Run Code Online (Sandbox Code Playgroud)

谢谢你。