Javascript 为什么打字稿显示“打印”字样;无法调用可能为';未定义';。ts(2722)“;可选链接运算符后出错?

Javascript 为什么打字稿显示“打印”字样;无法调用可能为';未定义';。ts(2722)“;可选链接运算符后出错?,javascript,typescript,undefined,optional-chaining,Javascript,Typescript,Undefined,Optional Chaining,在此逗留期间,我决定深入研究TypeScript,并开始通过实现一些基本数据结构来实践它。我试图实现一个使用自定义节点的自定义堆栈 我的堆栈节点定义如下: 类堆栈节点{ 私人增值税:任何; 私有nxt:StackNode |未定义=未定义; 构造函数(val:any,nxt?:StackNode |未定义){ this.val=val; this.nxt=nxt | |未定义; } 获取值():任意{ 返回此.value; } get next():StackNode |未定义{ 把这个还给我,

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

我的堆栈节点定义如下:

类堆栈节点{
私人增值税:任何;
私有nxt:StackNode |未定义=未定义;
构造函数(val:any,nxt?:StackNode |未定义){
this.val=val;
this.nxt=nxt | |未定义;
}
获取值():任意{
返回此.value;
}
get next():StackNode |未定义{
把这个还给我,下一个;
}
}
导出默认堆栈节点;
和实际堆栈:

类堆栈{
私人容量!:数字;
私有顶部?:StackNode |未定义=未定义;
私有大小:数字=0;
构造函数(容量:数字,初始值?:数组){
这个。容量=容量;
if(初始值){
this.size=initialValues.length;
this.top=this.\u initStack(initialValues,initialValues.length-1);
}
};
private\u initStack=(数组:array,idx:number):StackNode=>{
如果(idx==0){
返回新的StackNode(数组[idx],未定义);
}否则{
返回新的StackNode(数组[idx],this.\u initStack(数组,idx-1));
}
}
pop():任何{
常量值=此.top?.value();
this.top=this.top?.next();
返回值;
}
}
导出默认堆栈;
这里的问题是pop方法中带有可选链接运算符的行
this.top=this.top?.next()

我所理解的是表达式
this.top?.next()
应该与

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

但我还是得到了错误

无法调用可能为“未定义”的对象。ts(2722)

当呼叫发出时,即使在该阶段不应再未定义

为什么?我错过了什么?StackNode.nxt和Stack.top都允许未定义。我试着用老办法这样做:

if(this.top!==null | | this.top!==未定义){
常量值=this.top.value()
this.top=this.top.next()
}
但是我仍然得到了相同的错误,即使这里应该确保
this.top
不能是未定义的,但必须是,或者至少应该是StackNode类型

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


我使用的是TS 3.8.3

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

const value=this.top?.value()的唯一原因甚至编译都是因为您使用了“any”(永远不要这样做!!),typescript假设
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;
  }

}
类堆栈节点{
私有val:T;
私有nxt:StackNode |未定义=未定义;
构造函数(val:T,nxt?:StackNode |未定义){
this.val=val;
this.nxt=nxt | |未定义;
}
获取值():T{
返回此.value;
}
get next():StackNode{
把这个还给我,下一个;
}
}
类堆栈{
私人容量!:数字;
私有顶部?:StackNode |未定义=未定义;
私有大小:数字=0;
构造函数(容量:数字,初始值?:数组){
这个。容量=容量;
if(初始值){
this.size=initialValues.length;
this.top=this.\u initStack(initialValues,initialValues.length-1);
}
};
private\u initStack=(数组:array,idx:number):StackNode=>{
如果(idx==0){
返回新的StackNode(数组[idx],未定义);
}否则{
返回新的StackNode(数组[idx],this.\u initStack(数组,idx-1));
}
}
pop():T |未定义{
const value=this.top?.value();//不编译
this.top=this.top?.next();//也不编译
返回值;
}
}

然后,
const value=this.top?.value()
也不会编译。

在您学习typescript时,我已经编辑了我的答案,以包含一个泛型示例来解决此问题。祝你一切顺利!哦,好吧,这是我完全错过的!思想获取者和其他方法一样可以访问。至于“any”,很可能有更好的方法,但目前我不知道它是什么。@zaplec重新加载你的页面,我用更好的方法编辑:)当我发布时,你已经用细节编辑了你的答案:D非常感谢!我也会检查泛型。非常感谢您的回答!