Last active
May 20, 2018 05:14
-
-
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 file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* 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