I would like to create a type guard function which checks for multiple types. It should be a mix of typeof operator and instanceof operator.
I started with the following implementation:
function typeof(obj: any, type: "string"): obj is string;
function typeof(obj: any, type: "number"): obj is number;
And I am using it the following way:
function do(value: any) {
let str: string = "";
let num: number = 0;
if(typeof(value, "string")){
str = value;
}
if(typeof(value, "number")){
num = value;
}
}
The function should also check against objects e.g. Date:
let date: Date = null;
if(typeof(value, Date)){
date = value;
}
I tried:
function typeof<K>(obj: any, type: K): obj is K;
But Typescript only show DateContructor if type is Date.
My final goal is a function which can check multiple types:
function typeof(obj, ...types:[]): ???
let date: Date = new Date();
//if(typeof value === "number" || value instanceof Date)
if(typeof(value, "number", Date)){
date = date value;
}
How should the typeOf function should be defined?
CodePudding user response:
For the strings to work, we need a predefined map of strings to their respective types first:
type TypeofMap = {
string: string;
number: number;
boolean: boolean;
symbol: symbol;
undefined: undefined;
object: object;
function: (...args: any[]) => any;
bigint: bigint;
};
Then we can lookup the correct type later:
type ToType<T> =
T extends keyof TypeofMap
? TypeofMap[T]
: T extends new (...args: any[]) => infer R
? R
: T;
I've also made it so that if T
is a constructor, then the type should be an instance of T
. Otherwise, I don't know anything else, so I will use T
itself as the type.
Here's the signature for typeOf
(note the capitalization on O, you cannot name functions "typeof"):
declare function typeOf<T extends keyof TypeofMap | {} | null | undefined>(value: any, type: T): value is ToType<T>;
The generic constraint looks weird because I wanted the function to autocomplete keys in TypeofMap
if you try to pass a string for the type, but it should still allow any type. Since {} | null | undefined
represents any possible value, but is different from keyof TypeofMap
, I still get autocomplete and the union is not reduced to only {} | null | undefined
.