Reputation: 2250
I have two types: (() => any) | undefined
and () => any
. I would like extract the return type of the function but only if the value is definitely not undefined.
I have tried the following:
type IsUndefined<T> = T extends (() => any) ? "no" : "yes";
But this resolves to "yes" | "no"
when the type is not undefined. I want to detect the difference between these types without creating a union.
Please see this playground link for an example.
That is the short story, the long story is that I have a struct like the following:
type MyStruct = {
optionalHook?: ((...args: any) => any) | undefined,
requiredHook: (...args: any) => any,
}
I would like to extract the return type of the optional hook, but only when it exists. I would like to extract the return type of the required hook otherwise.
See this playground link for a more comprehensive example.
Upvotes: 2
Views: 262
Reputation: 31805
Not sure why the absence of optionalHook
doesn't infer T
to undefined
in createStruct
but I've managed to get the desired result by adding default generic parameters:
// Create the generic struct
type MyStruct<T extends ((...args: any) => any) | undefined, U extends (...args: any) => any> = {
optionalHook?: T,
requiredHook: U,
}
// Utility function for easily creating stucts with the correct type.
// Without this I'd have to type the generic arguments manually for every struct instance.
function createStruct<T extends ((...args: any) => any) | undefined = undefined, U extends (...args: any) => any = (...args: any) => any>(struct: MyStruct<T, U>) {
return struct;
}
const withOptional = createStruct({
optionalHook: () => 5,
requiredHook: () => "hello",
});
const withoutOptional = createStruct({
requiredHook: () => true,
});
// The function for extracting the return type
type getReturnType<T> =
T extends MyStruct<infer O, infer R> ?
O extends (...args: any) => infer OR ?
OR :
R extends (...args: any) => infer RR ? RR : never :
never;
type ResultWithOptional = getReturnType<typeof withOptional>;
type ResultWithoutOptional = getReturnType<typeof withoutOptional>;
Explicitly set optionalHook
to undefined
also works:
Upvotes: 2
Reputation: 2388
You can use a custom util like this:
export const isSet = <T>(value: T | null | undefined): value is T => {
return value != null;
};
And then use it:
let something; // (() => any) | undefined
if (isSet(something)) {
doSomething(something); // () => any
}
And if you need the opposite (i.e. check that a type is undefined), then you don't even need a custom util, you can use lodash — either isUndefined or isNil (= is undefined or null).
Upvotes: 1