处理 TypeScript 中未初始化 class 值的最佳方法 - 对象可能是 'null'

Best way to handle uninitialised class values in TypeScript - Object is possibly 'null'

我已经为 S3 操作创建了一个包装器 class,但是当我使用 TypeScript 编译器进行编译时,出现以下错误:

lib/Store.ts:20:15 - error TS2531: Object is possibly 'null'.

20         await this.store.upload({

我是 TypeScript 的新手,但我知道 TypeScript 正在做它的工作,并防止 await this.store.upload() 可以 运行 而 this.storenull 的可能性。处理这种 class 值可能尚未初始化的情况的正确方法是什么?

我的包装纸 class:

import S3 from 'aws-sdk/clients/s3';

export class Store {
    storeName: string;
    store: S3 | null;
    initialised: boolean;
   
    constructor(storeName: string) {
        this.storeName = storeName;
        this.store = null;
        this.initialised = false;
    }
    
    _init(): void {
        this.store = new S3();
    }

    async _writeToStore(data: object, path: string): Promise<void>  {
        if (!this.initialised) this._init();
        await this.store.upload({
            Bucket: this.storeName,
            Key: path,
            Body: data
        }).promise();
    }
}

我一直试图避免在构造函数中创建 classes 的新实例,因为模拟起来很尴尬。 也许将新的 class 实例传递给构造函数是最好的方法?

你可以试试
{
...
“strictNullChecks”:真,
"strictPropertyInitialization": true,
...
}

"strictNullChecks" 告诉编译器注意任何评估为 null 或 undefined 的声明变量,并在编译时引发错误 (https://www.typescriptlang.org/tsconfig#strictNullChecks) “strictPropertyInitialization”告诉编译器引发错误 'when a class 属性 when a class 属性 was declared but not set in the构造函数'。 (https://www.typescriptlang.org/tsconfig#strictPropertyInitialization)

Typescript 给你这个错误是因为你启用了 strictNullChecks 并且你的 属性 storenull 作为可能的类型。

您可以执行这些选项中的任何一个

选项 1 - 删除 null 类型

您可能可以在 store 上删除 null 类型,因为您在构造函数中设置 属性 的值,而您的代码中没有任何内容将其设置为 null:

  store: S3;

选项 2 - 添加 non-null 断言运算符

或者,如果在执行 this.store.upload({...})this.store 永远不会为空,那么您可以像这样添加 non-null assertion operator (!)

  this.store!.upload({...})

这将告诉 Typescript 停止给出错误。请注意,这不会更改代码的运行时行为,因此仅在知道值不能为 nullundefined.[=33 时才使用 ! 很重要=]

选项 3 - 在

之前检查 storenull

您可以在调用 this.store.upload() 之前明确检查 this.store 是否存在空值。但是这个调用必须在同一个方法中完成,像这样:

   if (!this.store) {
      this.store = new S3();
   }
   await this.store.upload({...});

这行不通:

   if (!this.store) {
      this._init();
   }
   await this.store.upload({...});

结论

就个人而言,我会选择选项 1。我假设您为 S3 编写包装器的原因是您的消费者永远不必实例化并直接使用 S3对象,而是实例化并使用包装器 class/object.