-
Notifications
You must be signed in to change notification settings - Fork 12.8k
is
type guards for properties
#11796
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
This declare class File {
// ...
/**
* Type: Buffer|Stream|null (Default: null)
*/
private contents: Buffer | NodeJS.ReadableStream;
/**
* Returns true if file.contents is a Buffer.
*/
public isBuffer(): this is { contents: Buffer };
/**
* Returns true if file.contents is a Stream.
*/
public isStream(): this is { contents: NodeJS.ReadableStream };
}
const f = new File();
if (f.isBuffer()) {
console.log(f.contents.buffer);
} else if (f.isStream()) {
console.log(f.contents.read(1024));
} |
Note, you can also write isBuffer(): this is this & { contents: Buffer }; Which will propagate the instance type for further refinement while allowing you to access |
However, it doesn't work exactly like type guards usually work. Inside this
Still great that it works. |
@thorn0, in the future subset types might be able to help with this. For now, you can use this, which is actually shorter and arguably more readable interface FileBuffer {
kind: 'buffer';
contents: Buffer;
}
interface FileStream {
kind: 'stream';
contents: NodeJS.ReadableStream;
}
type File = FileBuffer | FileStream;
declare const File: new () => File;
const f = new File();
if (f.kind === 'stream' && f.kind === 'buffer') // error |
interface FileBuffer {
isBuffer: true;
contents: Buffer;
}
interface FileStream {
isBuffer: false;
contents: NodeJS.ReadableStream;
}
type File = FileBuffer | FileStream;
declare const File: new () => File;
const f = new File();
if (f.isBuffer) {
f.contents; // Buffer
} else {
f.contents; // NodeJS.ReadableStream
} |
I'm not the author of the library. I just wanted to improve its type definitions. |
@Aleksey-Bykov Indeed, that is much more elegant. @thorn0 I messed around a little bit and was able to get the mutually exclusive interface FileBuffer {
contents: Buffer;
isBuffer(): true;
isStream(): this is never;
}
interface FileStream {
contents: NodeJS.ReadableStream;
isStream(): true;
isBuffer(): this is never;
}
interface File {
contents: Buffer | NodeJS.ReadableStream;
isBuffer(): this is FileBuffer;
isStream(): this is FileStream;
}
declare const File: new () => File;
// ...
const f = new File();
if (f.isBuffer()) {
console.log(f.contents.buffer);
}
if (f.isStream()) {
console.log(f.contents.read(1024));
}
if (f.isBuffer() && f.isStream()) {
f.contents; //'Property 'contents' does not exist on type 'never'.
} Not exactly what you asked for in that |
@aluanhaddad It works. :) Ta-da: DefinitelyTyped/DefinitelyTyped#12368 🎉 |
@thorn0 should I leave this issue open? |
I honestly don't know. The solution that @aluanhaddad found looks hackish, but it allowed me to achieve what I wanted. So far it's the first and only time I needed a type guard like |
If it can be accomplished through reasonable means I'd prefer to not do extra work / add complexity unless it's really needed. I'll retag for now in case anyone else runs into something similar and can't use the same method. |
Seems like this is good enough |
TypeScript Version: 2.0.3
Code
From the typings for the
vinyl
module.Expected behavior:
Possibility to specify something like
this.contents is Buffer
instead of justboolean
for the return type of the methodsisBuffer
,isStream
,isNull
.Actual behavior:
The language doesn't support this.
The text was updated successfully, but these errors were encountered: