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'sinject
function, 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 theInjectionToken
class: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> | T
by the fact thattypeof
returnsfunction
for 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 Type
returnstrue
for the third, but also the first case.typeof x === 'function'
(unsurprisingly) returnstrue
for the first and the third case, as well.typeof x === 'function' && Object.prototype.hasOwnProperty.call(x, 'constructor')
, on the other hand, returnsfalse
in all cases.