abstract class Base {
protected id: number | null = null;
init(id: number) {
this.id = id;
}
isIdSet(_ = this.id): _ is null | never {
if (this.id === null) throw new Error(ERROR_NO_ID);
else return false;
}
}
class Foo extends Base {
private fetch(id: number) { ... }
get(): Observable<string> {
if (this.isIdSet()) {
return this.fetch(this.id); // TS2322: Type 'number | null' is not assignable to type 'number'.
}
}
}
CodePudding user response:
TypeScript will be smart enough to narrow id
's type to number
if you check that it is not null
on a variable defined inside the same function scope. Otherwise, it can't foresee the execution order and narrow the variable types.
get(): Observable<string> {
const id = this.id; // number | null
if (id !== null) {
return this.fetch(this.id); // number
}
}
CodePudding user response:
You may be looking for an assertion function.
abstract class Base {
protected id: number | null = null;
init(id: number) {
this.id = id;
}
isIdSet(_ = this.id): asserts _ is number {
if (this.id === null) throw new Error("ERROR_NO_ID");
}
}
class Foo extends Base {
private fetch(id: number) {}
get() {
this.isIdSet(this.id)
return this.fetch(this.id);
}
}
CodePudding user response:
The idea was to put he null-check and throw into a function to get rid of duplicate if statements
You can do this in the base class with a custom getter that checks if this.m_id
is defined and throws an error otherwise, essentially forcing the init
method to be called before accessing id
.
class Base {
private m_id: number | null = null;
protected get id(): number {
if(this.m_id === null){
throw new Error(`Id is not defined`);
}
return this.m_id;
}
public init(a_id: number): void {
this.m_id = a_id;
}
}
class Foo extends Base {
private fetch(a_id: number): string {
return a_id.toString();
}
public get(): string {
return this.fetch(this.id);
}
}