与该问题相对应的一个简单示例“一个简单的通用类型且类型安全的LinkedList之类的数据结构”,其中每个下一个Node可以具有不同的类型。例如,目的是实现这一点:
interface LinkedNode<T1> {
value: T1;
next: LinkedNode<T2> | null; // Typescript gives error for T2 here.
}
Use case:
interface IPair{
a:boolean;
b: number;
}
let LinkedNode1: LinkedNode<string> = {value: "string1", next: null};
let LinkedNode2: LinkedNode<number> = {value: 10, next: LinkedNode1};
let LinkedNode3: LinkedNode<IPair> = {value: {a:true, b: 2}, next: LinkedNode2};
let root: LinkedNode<boolean> = {value: true, next: LinkedNode3};
let x = root.next.value.a; // ultimately this is the desired effect: to be able to get access to other linked node's member variables without having to manually typecast.
因此,问题是:“对于上面的LinkedNode<T1>
接口,用<T2>
替换<any>
会编译,但是会丢失类型信息。是否可以在不使用的情况下实现上述预期的效果用<any>
代替<T2>
?如果不是,那还有什么选择?”
答案 0 :(得分:3)
如果我对您的理解正确,那么您真的想要一种tuple类型的元组,其中元组中的每个元素都向下一层向下进入您的树。或至少这对我来说唯一有意义,因为您必须根据所有后代的类型来定义根节点的类型。
给出几个tuple-related features added in TypeScript 3.0,您可以执行以下操作:
// get the first element of a tuple; Head<[1,2,3]> is 1
type Head<L extends any[]> =
((...l: L) => void) extends ((h: infer H, ...t: infer T) => void) ? H : never;
// get the tuple with the first element removed; Tail<[1,2,3]> is [2,3]
type Tail<L extends any[]> =
((...l: L) => void) extends ((h: infer H, ...t: infer T) => void) ? T : never;
// represent LinkedNode in the following nested way
interface LinkedNode<T extends any[]> {
value: Head<T>;
next: LinkedNode<Tail<T>> | null;
}
当您到达元组的末尾时,会有一些有趣的事情(LinkedNode<[]>
和LinkedNode<never>
是有趣的类型),但是| null
足以掩盖它。
让我们尝试一下:
const node: LinkedNode<[string, number, boolean]> = {
value: "a",
next: {
value: 1,
next: {
value: true,
next: null
}
}
};
let LinkedNode1: LinkedNode<[string]> = { value: "string1", next: null };
let LinkedNode2: LinkedNode<[number, string]> = { value: 10, next: LinkedNode1 };
let LinkedNode3: LinkedNode<[IPair, number, string]> = { value: { a: true, b: 2 }, next: LinkedNode2 };
let root: LinkedNode<[boolean, IPair, number, string]> = { value: true, next: LinkedNode3 };
对我很好。
在TS3.0之前,您可以获得带有嵌套泛型的东西,这可能更简单:
interface LinkedNode<T, N extends null | LinkedNode<any, any>=null> {
value: T;
next: N;
}
const node: LinkedNode<string, LinkedNode<number, LinkedNode<boolean>>> = {
value: "a",
next: {
value: 1,
next: {
value: true,
next: null
}
}
};
let LinkedNode1: LinkedNode<string> = {value: "string1", next: null};
let LinkedNode2: LinkedNode<number, typeof LinkedNode1> = {value: 10, next: LinkedNode1};
let LinkedNode3: LinkedNode<IPair, typeof LinkedNode2> = {value: {a:true, b: 2}, next: LinkedNode2};
let root: LinkedNode<boolean, typeof LinkedNode3> = {value: true, next: LinkedNode3};
看起来也不错。这些帮助之一吗?