1

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

我的 StackNode 定义如下:

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;

这里的问题是pop-method 中可选链接运算符的行this.top = this.top?.next()

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

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

但我仍然收到错误

无法调用可能是“未定义”的对象。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 类型。

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

我正在使用 TS 3.8.3

4

1 回答 1

1

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

甚至编译的唯一原因const value = this.top?.value();是因为您使用“任何”(不要这样做,永远!!),并且打字稿假定这get value可能会返回您正在调用的函数。

您应该使用泛型定义 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();也不会编译。

于 2020-04-05T18:00:36.090 回答