Add an expression that makes type guard functions to check the class instance members instead of
the function's parameters, in place of value is X something like this.value is X.
This would be handy when checking if an instance field is of one type or another, in join types or
in optional types.
Currently this can be achieved with parameter checking, like:
class Foo {
value: string | null;
hasValue(value: string | null): value is string {
return value !== null;
}
}
const foo = new Foo();
if (foo.hasValue(foo.value)) {
// Do something with foo that involves value not being null.
}
The problem of this approach is that if you want to maintain the member field _private_, you can't
take this approach, or this approach can only be used inside the class (Therefore hasValue should
be also private).
The latter can be solved telling Typescript to check the instance's member instead of the function
parameter:
class Foo {
private value: string | null;
public hasValue(): this.value is string {
return this.value !== null;
}
}
const foo = new Foo();
if (foo.hasValue()) {
// Do something with foo that involves value not being null.
}
My suggestion meets these guidelines:
You can already do this:
class Foo {
public value: string | null;
public hasValue(): this is { value: string } {
return this.value !== null;
}
}
const foo = new Foo();
foo.value.toString(); // Error, may be null
if (foo.hasValue()) {
// OK
foo.value.toString();
}
Yes, it can be used as a solution and works fine (Thanks for the answer).
However, the field cannot be private:
TS2546: Property 'value' has conflicting declarations and is inaccessible in type 'Optional & { value: any; }'.
(But with public field works, which is better than passing it again)
There's no point to provide a public type guard on a private member, though - if you're inside the class, you can already directly test against it; if you're outside the class, the fact that the private field isn't null doesn't change what you can do with the class instance.
So we can say that is a good pattern to check it internally using a static type guard, like:
class Foo<T> {
private static check<T>(value: T | null): type is T {
return value !== null;
}
private bar: T | null = null;
public operation() {
// or: if (this.bar !== null) {...}
if (Foo.check<T>(this.bar)) {
// Do things.
}
}
}
In which case, this can replace the explicit member guard.
The original intention was to provide a boolean-style method, like hasValue() that could let the compiler
know if what a getter returns is valid, but can be replaced with the other way round approach: Get the value, then checking if it was valid. I'll close this as it can be achieved with other approaches. Thanks for your time!
You can already do this:
class Foo { public value: string | null; public hasValue(): this is { value: string } { return this.value !== null; } } const foo = new Foo(); foo.value.toString(); // Error, may be null if (foo.hasValue()) { // OK foo.value.toString(); }
This doesn't actually work as expected if we use an else clause after the last if:
...
if (foo.hasValue()) {
// OK
foo.value.toString();
} else {
(foo.value); // Should be null, but is actually string | null
}
In the last else clause, TypeScript cannot figure out that foo.value can only be null there. Any ways around this?
Most helpful comment
This doesn't actually work as expected if we use an
elseclause after the lastif:In the last
elseclause, TypeScript cannot figure out thatfoo.valuecan only benullthere. Any ways around this?