I've got a type definition that allows for various ways of supplying an object:
type ObjSource<T> = InjectionToken<T> | Type<T> | ((context: IContext) => (T | Promise<T>)) | Promise<T> | T;
In there, IContext is an interface of my own that provides some context information about (a part of) my application.
To properly evaluate all of these, I need to find out what object source was actually supplied. I'm trying to do so with custom type guard functions. Let's start:
- If the value is of type
InjectionToken<T>orType<T>, I'd simply like to stuff it into Angular'sinjectfunction, thereby letting Angular's dependency injection deal with it. - If the value is of type
((context: IContext) => (T | Promise<T>)), I'd like to execute that function and pass the result toPromise.resolve. - Otherwise, i.e. if the value is of type
Promise<T>orT, I'd like to pass it toPromise.resolve.
Now, how can I distinguish these cases?
- I think I can recognize an
InjectionToken<T>by virtue of it being an instance of theInjectionTokenclass:function isInjectionToken<T>(x: ObjSource<T>): x is InjectionToken<T> { return x instanceof InjectionToken; } - I know next to nothing about
T. I might be able to restrict it toT extends object. In that case, I distinguish(context: IContext) => (T | Promise<T>)fromPromise<T> | Tby the fact thattypeofreturnsfunctionfor the former, but not the latter.
But how do I distinguish Type<T> from (context: IContext) => (T | Promise<T>)?
Angular's Type<T> is defined as:
class Type<T> extends Function {
constructor(...args: any[]): T
}
Using a tiny sample Angular app, I've tried various implementations for isType<T>(x: ProviderToken<T>): x is Type<T> in here:
export class App {
public doClick() {
const a = isType(function blah() {
return true;
});
const b = isType(new InjectionToken<string>('xyz'));
const c = isType(App);
alert(`${a} ${b} ${c}`);
}
}
So far, though, I have not been able to find the right criteria to check:
x instanceof Typereturnstruefor the third, but also the first case.typeof x === 'function'(unsurprisingly) returnstruefor the first and the third case, as well.typeof x === 'function' && Object.prototype.hasOwnProperty.call(x, 'constructor'), on the other hand, returnsfalsein all cases.