I'm reading the Classes section of the handbook, but there is a difference that makes me confused.
In the following examples:
In Example 1, they first explicitly wrote the return type this is Networked & this
. I can understand this part.
Then, in Example 2, they only did this is { value: T }
, but the type of box
in the if
-block is Box<string> & { value: string; }
.
I don't know why the second case works. Based on the first example, I expect that it should be this is { value: T } & this
instead. Does it mean I can always omit the explicit & this
?
class FileSystemObject {
isFile(): this is FileRep {
return this instanceof FileRep;
}
isDirectory(): this is Directory {
return this instanceof Directory;
}
isNetworked(): this is Networked & this { // the return type here.
return this.networked;
}
constructor(public path: string, private networked: boolean) {}
}
class FileRep extends FileSystemObject {
constructor(path: string, public content: string) {
super(path, false);
}
}
class Directory extends FileSystemObject {
children: FileSystemObject[];
}
interface Networked { // this interface that matters.
host: string;
}
const fso: FileSystemObject = new FileRep("foo/bar.txt", "foo");
if (fso.isFile()) {
fso.content;
} else if (fso.isDirectory()) {
fso.children;
} else if (fso.isNetworked()) {
fso.host; // const fso: Networked & FileSystemObject
}
class Box<T> {
value?: T;
hasValue(): this is { value: T } { // here, there is no `& this`.
return this.value !== undefined;
}
}
const box = new Box<string>();
box.value = "Gameboy";
if (box.hasValue()) {
box.value; // notice the type of box here.
}
Tried it just in case: yes, you can omit this
. The type guard is always performed on the this
instance, the narrowed version is always some variant of this
, typescript is smart enough to do that.
Works the same as Extract
https://www.typescriptlang.org/docs/handbook/utility-types.html#extracttype-union