TypeScript链表实现中逻辑与/或判断引发的类型错误咨询
我正在学习TypeScript与类型安全(防御式编程),尝试用TypeScript实现链表时遇到一个问题:将代码中if (!this.head || !this.tail)的逻辑或(||)改为逻辑与(&&)后,const oldTail: NodeItem = this.tail;行会抛出如下类型错误:
Type 'NodeItem | null' is not assignable to type 'NodeItem'.
Type 'null' is not assignable to type 'NodeItem'.
相关核心代码块
add(value: any): NodeItem { const newItem: NodeItem = { value: value, next: null }; if (!this.head || !this.tail) { this.head = newItem; this.tail = this.head; this.total++; return newItem; } const oldTail: NodeItem = this.tail; this.tail = newItem; oldTail.next = this.tail; this.total = this.total++; return newItem; }
完整代码上下文
type NodeItem = { value: any; next: NodeItem | null; }; class LinkedList { head: NodeItem | null = null; tail: NodeItem | null = null; total: number; constructor(value?: any) { value && this.add(value); } add(value: any): NodeItem { const newItem: NodeItem = { value: value, next: null }; if (!this.head || !this.tail) { this.head = newItem; this.tail = this.head; this.total++; return newItem; } const oldTail: NodeItem = this.tail; this.tail = newItem; oldTail.next = this.tail; this.total = this.total++; return newItem; } print(): void {} }
错误原因分析
原逻辑(||)的作用
原代码中if (!this.head || !this.tail)的逻辑是:只要head或tail其中一个为null,就进入分支。对于正常的链表来说,head和tail的状态是一致的——要么都为null(空链表),要么都不为null(存在元素)。所以这个分支实际处理的是空链表的初始化场景:创建新节点后同时赋值给head和tail,然后直接return,跳过后续代码。
此时TypeScript可以明确推断:后续代码执行时,this.head和this.tail一定都不为null,所以const oldTail: NodeItem = this.tail;的类型赋值是安全的,不会报错。
修改后逻辑(&&)的问题
当把||改成&&后,条件变为!this.head && !this.tail,意思是只有当head和tail同时为null时才进入分支。这就导致分支外的场景包含三种可能:
this.head不为null,但this.tail为nullthis.tail不为null,但this.head为nullthis.head和this.tail都不为null
TypeScript无法确定此时this.tail一定不是null,所以将它赋值给类型为NodeItem的oldTail时,就会触发类型不兼容的错误——因为this.tail的类型是NodeItem | null,可能为null,不能直接赋值给非空的NodeItem类型变量。
另外从业务逻辑上看,链表的head和tail状态不一致本身就是异常情况,原代码的||逻辑正是为了避免这种异常,保证后续代码的类型安全。
内容的提问来源于stack exchange,提问作者atolz

