I've created a wrapper class for S3 operations but when I compile using the TypeScript complier I get the following error:
lib/Store.ts:20:15 - error TS2531: Object is possibly 'null'.
20 await this.store.upload({
I'm new to TypeScript but I understand TypeScript is doing it's job here and preventing the possibility that await this.store.upload()
could run while this.store
is null
. What's the correct way for dealing with this type of situation where a class value might not yet be initialised?
My wrapper 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 = new S3();
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();
}
}
I've always tried to avoid creating new instances of classes in the constructor because it's awkward to mock. Maybe passing a new class instance into the constructor is the best approach?
CodePudding user response:
You can try
{
...
"strictNullChecks": true,
"strictPropertyInitialization": true,
...
}
"strictNullChecks" tells the compiler to watch for any declared variables that evaluate to null or undefined and raise on error on at compiler time (https://www.typescriptlang.org/tsconfig#strictNullChecks) "strictPropertyInitialization" tells the compiler to raise an error 'when a class property was declared but not set in the constructor'. (https://www.typescriptlang.org/tsconfig#strictPropertyInitialization)
CodePudding user response:
Typescript is giving you that error because you have strictNullChecks
enabled and your property store
has null
as a possible type.
You can do any of these options
Option 1 - Remove null
type
You can probably drop the null
type on store
, since you are setting the value of that property on your constructor, and nothing on your code sets it to null
:
store: S3;
Option 2 - Add non-null assertion operator
Alternatively, if this.store
is never going to be null when you execute this.store.upload({...})
, then you can add a non-null assertion operator (!) like this:
this.store!.upload({...})
That will tell Typescript to stop giving the error. Note that this doesn’t change the runtime behavior of your code, so it's important to only use !
when you know that the value can't be null
or undefined
.
Option 3 - Check store
for null
value right before
You can explicitly check this.store
for null value right before calling this.store.upload()
. But this call must be done within the same method, like this:
if (!this.store) {
this.store = new S3();
}
await this.store.upload({...});
This won't work:
if (!this.store) {
this._init();
}
await this.store.upload({...});
Conclusion
Personally, I would go with option 1. I'm assuming that your reason for writing a wrapper for S3
is so that your consumers never have to instantiate and work directly with an S3
object and instead instantiate and work with your wrapper class/object.