网站搜索

如何在 TypeScript 中区分 `(() => any) | undefined` 与单纯的 `() => any`?


我有两种类型:(() => any) | undefined 和 () => any。我想提取函数的返回类型,但仅在该值肯定不是 undefined 的情况下。

我尝试了以下方法:

type IsUndefined<T> = T extends (() => any) ? "no" : "yes";

但当类型不是 undefined 时,这将解析为 "yes" | "no"。我想在不创建联合类型的情况下检测这些类型之间的区别。

请查看这个游乐场链接以获取示例。

这是简短的故事,长故事是我有一个像下面这样的结构体:

type MyStruct = {
    optionalHook?: ((...args: any) => any) | undefined,
    requiredHook: (...args: any) => any,
}

我想提取可选钩子的返回类型,但仅在它存在时提取。否则,我想提取必需钩子的返回类型。

请参阅此 playground 链接以获取更全面的示例。

答案#1

不确定为什么在 createStruct 中缺少 optionalHook 并不会将 T 推断为 undefined,但我已经通过添加默认泛型参数得到了期望的结果:

// 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>;

TypeScript 游乐场

显式将 optionalHook 设置为 undefined 也可行:

TypeScript 游乐场

答案#2

你可以使用这样的自定义工具:

export const isSet = <T>(value: T | null | undefined): value is T => {
  return value != null;
};

然后使用它:

let something; // (() => any) | undefined
if (isSet(something)) {
  doSomething(something); // () => any
}

如果你需要相反的情况(即检查一个类型是否未定义),那么你甚至不需要自定义工具函数,你可以使用 lodash —— 可以使用 isUndefined 或 isNil(= 未定义或为空)。