Skip to content

Instantly share code, notes, and snippets.

@rozzzly
Last active May 20, 2018 05:14
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rozzzly/661eff3ea8f962d67fb4060889fc6a8f to your computer and use it in GitHub Desktop.
Save rozzzly/661eff3ea8f962d67fb4060889fc6a8f to your computer and use it in GitHub Desktop.
Typescript Negative TypeGuards in Promise Rejections: this doesn't exist.. but it would be cool if something like this did.. I guess
/**
* this doesn't exist.. but it would be cool if something like this did.. I guess
*
*/
interface BaseFile {
readonly path: string;
isValid: Promise<this is ValidFile>;
}
interface InvalidFile extends BaseFile {
errors: Error[];
lastError: Error | null;
}
interface ValidFile extends BaseFile {
uri: Uri;
}
class File implements BaseFile {
public static get(resource: string): File;
public static get(resource: Uri): ValidFile;
public static get(resource: string | Uri): File | ValidFile {
return new File(resource);
}
public path: string;
protected errors: Error[] = [];
protected get lastError(): Error | null {
return ((this.errors.length)
? this.errors[this.errors.length - 1]
: null
);
}
private _uri: Uri | null = null;
protected get uri(): Uri | null {
return this._uri;
}
private set uri(uri: Uri): void {
this._isValid = true;
this._uri = uri;
this.path = uri.fsPath;
}
private _isValid: boolean | null = null;
private async ensureValid(): Promise<this is ValidFile, this is InvalidFile> {
if (this.isValid === true) return this._isValid;
else {
this._isValid = null;
return this.isValid();
}
}
public async isValid(): Promise<this is ValidFile, this is InvalidFile> {
if (this._isValid !== null) return this._isValid;
else {
let uri: Uri;
let perms: number;
let error: Error;
try {
uri = await magicFS.resolve(this.path);
perms = await magicFS.checkPerms(this.uri);
} catch (e) {
error = e;
}
if (error) {
this.invalidate(error);
throw error;
} else {
if (perms === 0o777) {
this.uri = uri;
} else {
this.invalidate(new Error('bad permissions'));
}
}
}
private constructor(resource: string | Uri ) {
if (typeof resource === 'string') {
this.path = path;
} else {
this.uri = resource;
}
}
protected async create(): Promise<this is ValidFile, this is InvalidFile> {
if (!await this.ensureValid()) {
let error: Error;
try {
await magicFS.create(this.uri);
} catch (e) {
error = e;
}
if (error) {
throw this.invalidate(error);
}
} else {
throw new Error(`Cant delete an invalid file');
}
}
protected async delete(): Promise<void, this is InvalidFile> {
if (await this.isValid) {
let error: Error;
try {
await magicFS.delete(this.uri);
} catch (e) {
error = e;
}
if (error) {
throw this.invalidate(error);
}
} else {
throw new Error(`Cant delete an invalid file');
}
}
protected async read(): Promise<string, this is InvalidFile> {
if (await this.isValid) {
let content: string;
let error: Error;
try {
content = await magicFS.read(this.uri);
} catch (e) {
error = e;
}
if (error) {
throw this.invalidate(error);
} else {
return content;
}
} else {
throw new Error(`Cant read an invalid file');
}
}
private invalidate(error: Error): Error {
this.errors.push(error);
this._isValid = false;
return error;
}
}
```
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment