【发布时间】:2021-12-17 08:56:08
【问题描述】:
说我有类型
type Atom = string | boolean | number。我想定义一种数组类型:
NestedArray = Atom | [a_0, a_1, ... , a_n] 其中每个a_i 是Atom 或NestedArray。
这可以在 Typescript 中实现吗?
【问题讨论】:
标签: typescript
说我有类型
type Atom = string | boolean | number。我想定义一种数组类型:
NestedArray = Atom | [a_0, a_1, ... , a_n] 其中每个a_i 是Atom 或NestedArray。
这可以在 Typescript 中实现吗?
【问题讨论】:
标签: typescript
类型别名不能引用自己,所以这种幼稚的方法会失败:
type NestedArray = Atom | Array<NestedArray | Atom> //Type alias 'NestedArray' circularly references itself.
但是接口可以引用自己:
interface NestedArray extends Array<NestedArray | Atom> {
}
我们可以在顶层定义一个额外的联合来处理根案例:
type Atom = string | boolean | number
interface NestedArray extends Array<NestedArray | Atom> {
}
type AtomOrArray = Atom | NestedArray;
//Usage
let foo: AtomOrArray = [
"",
1,
[1, 2, ""]
]
let bar: AtomOrArray = ""
【讨论】:
现在 typescript 允许类型循环引用自身,例如:
type RArray = (string | RArray)[];
如果你想在递归函数中定义一个泛型,可以使用interface ...<T> extends (T|...<T>)[]
interface RA<T> extends Array<T | RA<T>> { }
例如,创建一个函数来递归地求和
function sum(arr: RA<number>) {
let res = 0;
arr.forEach((n) => {
if (Array.isArray(n)) {
res += sum(n);
} else {
res += n;
}
});
return res;
}
console.log(sum([1, 2, 3, [4, [5]], [[6]]]))
// output: 21
但是这种方式有一些缺点,编译器无法知道n的具体类型
arr.forEach((n) => {
if (Array.isArray(n)) { // typeof n: `number | RA<number>`
res += sum(n);
} else {
res += n;
}
});
【讨论】:
从 typescript 3.7 开始,您可以创建通用递归类型:
type Tree<T> = T | Array<Tree<T>>
然后像这样使用它:
let stuff: Tree<string | boolean | number> = ["lala", [1, "stuffy"], 3, false];
【讨论】: