为什么 TypeScript 在可选链接运算符后显示 "Cannot invoke an object which is possibly 'undefined'.ts(2722)" 错误?

Why is TypeScript showing "Cannot invoke an object which is possibly 'undefined'.ts(2722)" error after optional chaining operator?

在这段呆在家里的时间里,我决定深入研究 TypeScript,并开始通过实现一些基本数据结构来实践它。我正在尝试实现使用自定义节点的自定义堆栈。

我的 StackNodes 是这样定义的:

class StackNode {

  private val: any;
  private nxt: StackNode | undefined = undefined;

  constructor(val: any, nxt?: StackNode | undefined) {
    this.val = val;
    this.nxt = nxt || undefined;
  }

  get value(): any {
    return this.value;
  }

  get next(): StackNode | undefined {
    return this.next;
  }

}

export default StackNode;


实际堆栈:

class Stack {

  private capacity!: number;
  private top?: StackNode | undefined = undefined;
  private size: number = 0;

  constructor(capacity: number, initialValues?: Array<any>) {
    this.capacity = capacity;

    if (initialValues) {
      this.size = initialValues.length;
      this.top = this._initStack(initialValues, initialValues.length - 1);
    }

  };

  private _initStack = (array: Array<any>, idx: number): StackNode => {
    if (idx == 0) {
      return new StackNode(array[idx], undefined);
    } else {
      return new StackNode(array[idx], this._initStack(array, idx-1));
    }
  }

  pop(): any {
    const value = this.top?.value();
    this.top = this.top?.next();
    return value;
  }

}

export default Stack;

这里的问题是弹出方法 this.top = this.top?.next()

中带有 可选链接 运算符的行

我的理解是表达式 this.top?.next() 应该等同于

(this.top === null || this.top === undefined)? undefined : this.top.next()

但我仍然收到错误

Cannot invoke an object which is possibly 'undefined'.ts(2722)

当调用被调用时,即使在那个阶段它不应该再被定义。

这是为什么?我在这里错过了什么? StackNode.nxt 和 Stack.top 都允许未定义。我试过用这样的旧方法来做:

if (this.top !== null || this.top !== undefined) {
  const value = this.top.value()
  this.top = this.top.next()
}

但我仍然得到同样的错误,尽管这里应该确保 this.top 不能未定义,但必须是,或者至少应该是 StackNode 类型。

这应该是如何工作的,当从空堆栈弹出时,弹出方法将 return 未定义,当弹出最后一个元素时,它的下一个未定义的元素被设置为堆栈的顶部。

我正在使用 TS 3.8.3

您将 next 定义为 getter,因此必须像这样访问它:this.top = this.top?.next

const value = this.top?.value(); 甚至编译的唯一原因是因为你使用 'any'(永远不要那样做!!),并且打字稿假定 get value 可能 return您正在调用的函数。

您应该使用泛型定义 StackNode。例如,

class StackNode<T> {

  private val: T;
  private nxt: StackNode<T> | undefined = undefined;

  constructor(val: T, nxt?: StackNode<T> | undefined) {
    this.val = val;
    this.nxt = nxt || undefined;
  }

  get value(): T {
    return this.value;
  }

  get next(): StackNode<T> {
    return this.next;
  }

}


class Stack<T> {

  private capacity!: number;
  private top?: StackNode<T> | undefined = undefined;
  private size: number = 0;

  constructor(capacity: number, initialValues?: Array<any>) {
    this.capacity = capacity;

    if (initialValues) {
      this.size = initialValues.length;
      this.top = this._initStack(initialValues, initialValues.length - 1);
    }

  };

  private _initStack = (array: Array<any>, idx: number): StackNode<T> => {
    if (idx == 0) {
      return new StackNode(array[idx], undefined);
    } else {
      return new StackNode(array[idx], this._initStack(array, idx-1));
    }
  }

  pop(): T | undefined {
    const value = this.top?.value(); //doesn't compile
    this.top = this.top?.next(); //doesn't compile either
    return value;
  }

}

那么,const value = this.top?.value();也不会编译。