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'.
}
}
}
Asked
Active
Viewed 146 times
-1

Pavel Staselun
- 1,970
- 1
- 12
- 24
-
Sadly, this doesn't work because Typescript is unable to infer that `this.id` is not `null` from calling this function. You can use `if(this.id !== null)` instead. By definition, it will be a number if this resolves to `true`. – Jul 04 '22 at 13:12
-
The idea was to put he null-check and `throw` into a function to get rid of duplicate `if` statements, but now I realize - I'd have `if` statement anyway, so no point in doing that. – Pavel Staselun Jul 04 '22 at 13:33
-
It'd be nice if you could include that in the question, I added an answer to avoid having to use `if` statements whenever you have to access `id` from outside. – Jul 04 '22 at 14:33
2 Answers
1
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);
}
}

Tobias S.
- 21,159
- 4
- 27
- 45
-
Cool, never heard of Assertion Functions before, thanks! But unfortunately it doesn't work if you don't pass any argument to `isIdSet`. – Pavel Staselun Jul 05 '22 at 11:16
1
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);
}
}