You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

TypeScript嵌套泛型问题:参数被解析为交叉类型而非联合类型

解决TypeScript泛型钩子中交叉类型替代联合类型的报错问题

问题原因

TypeScript在泛型函数registerHumanHook中无法正确窄化泛型参数K对应的HumanHook[K]类型,错误地将其解析为所有HumanHookName对应类型的交叉类型(而非预期的单个匹配类型),导致参数类型不兼容报错。

解决方案

在初始化humanHooks[name]时,使用精确的类型断言将对象指定为HumanHook[K],既保留TypeScript的类型校验能力,又能修正交叉类型的错误推断:

interface HumanFunctionTypeMap {
    eat: {
        name: string;
        diet: boolean;
        vegan: boolean;
    };

    drink: Array<{
        diet: boolean;
        regular: boolean;
        soda: boolean;
    }>;

    sleep: {
        dream: boolean;
        snooze: boolean;
    };
}

type HumanHookName = keyof HumanFunctionTypeMap;

type HumanHook = {
    [K in HumanHookName]?: {
        hooks: Array<(args: HumanFunctionTypeMap[K]) => void>;
        handler: (args: HumanFunctionTypeMap[K]) => void;
    };
};

interface RegisterHumanHook {
    <K extends HumanHookName>(name: K, hook: (args: HumanFunctionTypeMap[K]) => void): void;
}

const humanHooks: HumanHook = {};

export const registerHumanHook: RegisterHumanHook = (name, hook) => {
    if (!humanHooks[name]) {
        // 关键修改:用精确断言指定当前K对应的钩子类型
        humanHooks[name] = {
            hooks: [],
            handler: args => {
                humanHooks[name]?.hooks.forEach(hook => hook(args));
            }
        } as HumanHook[K];
    }
    humanHooks[name]?.hooks?.push(hook);
};

方案说明

  • as HumanHook[K]明确告诉TypeScript,当前初始化的对象完全匹配泛型参数K对应的钩子类型,而非所有可能类型的交叉集合。
  • 相比宽泛的类型断言(如as any或as HumanHookName),该方式保留了对hooks和handler参数的严格类型校验,确保后续添加的钩子与当前name对应的参数类型一致。

可选优化

若想进一步增强类型追踪能力,可以用泛型辅助函数初始化humanHooks,让TypeScript更清晰地识别每个key的类型:

function createHumanHooks<T extends HumanHook = HumanHook>(): T {
    return {} as T;
}

const humanHooks = createHumanHooks();

内容的提问来源于stack exchange,提问作者roi467

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 14:57:45