I have a function isBoolean
which checks whether a run time variable is boolean and returns the narrow type of true
or false
as a type (rather than just boolean
).
export type IsBoolean<T> = T extends boolean ? true : false;
export function isBoolean<T extends unknown>(i: T) {
return (typeof i === "boolean") as IsBoolean<T>;
}
The aim now is to put the function into a structure like this (along with other types):
const types = () => {
boolean: {
name: "boolean",
type: true as boolean,
is: isBoolean,
typeGuard: (v: unknown) => v is boolean => isBoolean(v)
}
type TypesApi = ReturnType<typeof types>;
At this stage there is no problem running the isBoolean
function like so:
const yup = types().boolean.is(true);
But to get to the next stage I'm going to have to move away from my inferred types and start typing things more explicitly. What I'm wanting to be able to do is:
const myType = type(t => t.boolean);
To do this I have created a new type called Type
:
type Type<T extends any> = {
name: string;
type: T;
is: <V extends unknown>(v: V) => true | false,
typeGuard: (v: unknown) => v is T;
}
and then the type function looks like this:
type TypeDefinition<T extends any> = (defn: TypeApi) => T;
function type<T extends any>(fn: TypeDefinition<T>) {
return fn(typeApi());
}
This is then aided by explicit typing in the dictionary:
const types = () => ({
boolean: {
name: "boolean",
type: true as boolean,
is: isBoolean,
typeGuard: (v: unknown): v is boolean => isBoolean(v),
} as Type<boolean>
});
Sadly now when we try to use the API style the is
function which is an alias for isBoolean
no longer works:
const myType = type(t => t.boolean);
// type is now "boolean" instead of "true"
const yup3 = myType.is(true);
What can I do to get back this narrow typing which had before?