【发布时间】:2020-05-26 13:25:58
【问题描述】:
为了举例,考虑 TypeScript 3.7.5 中的最小链表类。一个LinkedList<T> 由一个ListNode<T> 链组成,其中类型变量T 在两者中指代相同的类型。还假设您使用LinkedList 中的私有静态字段来隐藏ListNode,因为它是不相关的实现细节。
class LinkedList<T> {
private head: ??? = null;
private tail: ??? = null;
private static ListNode = class ListNode<T> {
constructor(
public val: T | null,
public next: ListNode<T> | null) {}
};
append(item: T): this {
if (!this.tail) {
this.tail = {val: item, next: null};
this.head = this.tail;
} else {
this.tail.next = {val: item, next: null};
this.tail = this.tail.next;
}
return this;
};
remove(): T {
if (!this.head || this.head.val === null) {
throw Error();
} else {
const t = this.head.val;
this.head = this.head.next;
return t;
}
}
}
我如何表示上面的类型????它不是List.ListNode 或List.ListNode<T>。这不是有效的 TypeScript(至少从 3.7.5 开始)。它也不是InstanceType<typeof List.ListNode>。这是一个有效的类型,但它丢失了泛型参数T,因此无法强制执行封闭类和嵌套类由相同类型参数化的约束。
现在我们通过引入虚拟head 并依靠类型推断来修改类:
class LinkedList<T> {
private head = LinkedList.makeNode<T>();
private tail = this.head.next;
private static makeNode<T>() {
return new this.ListNode<T>(null, null);
}
private static ListNode = class ListNode<T> {
constructor(
public val: T | null,
public next: ListNode<T> | null) {}
};
append(item: T): this {
if (!this.tail) {
this.head.next = {val: item, next: null};
this.tail = this.head.next;
} else {
this.tail.next = {val: item, next: null};
this.tail = this.tail.next;
}
return this;
};
remove(): T {
if (!this.head.next || this.head.next.val === null) {
throw Error();
} else {
const t = this.head.next.val;
this.head.next = this.head.next.next;
return t;
}
}
}
给定这段代码,TypeScript 可以证明 remove() 实际上确实返回了 T 的实例。在悬停时,VSC 建议head 的类型是ListNode<T>。如何明确表达这种类型?
【问题讨论】:
-
在LinkedList里面嵌套ListNode的目的是什么?这条线试图实现什么:
private static ListNode = class ListNode<T> { } -
请考虑将上述代码转换为minimal reproducible example,可以将其放入the TypeScript playground 之类的独立IDE 中以演示您的问题。应该消除与您的问题无关的任何问题(例如,
List未声明,ListNode的属性未初始化),以便回答的人可以专注于正确的事情。祝你好运!
标签: typescript types