Last active
August 16, 2018 13:30
-
-
Save infloop/109a89e4980055ffffc30d0563eb3e68 to your computer and use it in GitHub Desktop.
instanceOf Typescript
This file contains hidden or 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
import {isImplements} from '../index'; | |
export type InterfaceTag<T> = ({ new (...args: any[]): T, readonly id: symbol }); | |
export function createInterface<I>(name: string): InterfaceTag<I>{ | |
let id = Symbol.for(name); | |
let interfaceTag = (class { | |
private static readonly identifier: symbol = id; | |
static [Symbol.hasInstance](instance) { | |
return isImplements(instance, this); | |
}; | |
public static get id(): symbol { | |
return this.identifier; | |
} | |
}); | |
Object.freeze(interfaceTag); | |
return (<InterfaceTag<I>>(<any> interfaceTag)); | |
} |
This file contains hidden or 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
import * as chai from 'chai'; | |
import 'reflect-metadata'; | |
import {implement, createInterface} from '../'; | |
const expect = chai.expect; | |
describe(`Interface '@implement' decorator`, async () => { | |
it('should work', async () => { | |
const IFoo = createInterface<IFoo>('IFoo'); | |
const IBar = createInterface<IBar>('IBar'); | |
interface IFoo { | |
helloFoo(): string; | |
} | |
interface IBar { | |
helloBar(): string; | |
} | |
@implement(IFoo) | |
class Foo implements IFoo { | |
helloFoo(): string { | |
return 'helloFoo'; | |
} | |
} | |
// TS warnings will also work without implements keyword | |
@implement(IBar) | |
class Bar { | |
helloBar(): string { | |
return 'helloBar'; | |
} | |
} | |
const foo = new Foo(); | |
const bar = new Bar(); | |
const baz = {}; | |
// magic! | |
expect(bar instanceof IFoo).to.be.equal(false); | |
expect(foo instanceof IFoo).to.be.equal(true); | |
if (bar instanceof IFoo) { | |
// TS type checking also works | |
bar.helloFoo(); | |
expect.fail('bar is not instance of IFoo'); | |
} | |
if (baz instanceof IFoo) { | |
// TS type checking also works | |
baz.helloFoo(); | |
expect.fail('baz is not instance of IFoo'); | |
} | |
}); | |
}); |
This file contains hidden or 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
import {TAG} from '../constants'; | |
import {InterfaceTag} from '../functions/createInterface'; | |
export function implement<T>(interfaceTag: InterfaceTag<T>) { | |
return function (target: {new (...args: any[]): T } ): any { | |
let tags: symbol[] = []; | |
if (interfaceTag instanceof Function) { | |
tags.push(interfaceTag.id); | |
} else { | |
throw new Error('interfaceTag must be a Function'); | |
} | |
if (Reflect.hasMetadata(TAG, target)) { | |
let existingTags = Reflect.getMetadata(TAG, target); | |
tags.push(...existingTags); | |
} | |
Reflect.defineMetadata(TAG, tags, target); | |
} | |
} |
This file contains hidden or 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
import {TAG} from '../constants'; | |
import {InterfaceTag} from './createInterface'; | |
export function isImplements<T>(target: T | any, interfaceTag: InterfaceTag<any>): target is T { | |
if (typeof target === 'undefined') { | |
return false; | |
} | |
if (Reflect.hasMetadata(TAG, target.constructor)) { | |
let tags: symbol[] = Reflect.getMetadata(TAG, target.constructor); | |
let tag: symbol; | |
if (interfaceTag instanceof Function) { | |
tag = interfaceTag.id; | |
} else { | |
throw new Error('interfaceTag must be a Function'); | |
} | |
return tags.indexOf(tag) >= 0; | |
} | |
return false; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment