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

TypeScript:移除components后如何让方法参数c类型为number而非never

TypeScript类型推断问题修复方案

问题描述

  • 注释掉[AAA.a1][BBB.b1]下的components: [1, 2]时,avaible方法的参数c类型变为never,期望为number
  • 注释该行后,所有条目(即使其他条目有components)的avaible参数都会变成(c: never) => {}
  • 未提供components属性时,方法参数c需回退为number而非never

原代码

enum AAA {
    a1 = 'a1', a2 = 'a2', a3 = 'a3',
}
enum BBB {
    b1 = 'b1', b2 = 'b2', b3 = 'b3',
}


type TestData<T extends number = number> = {
    components?: T[];
    avaible: (c: T) => void; 
}

type RR = Partial<Record<AAA, Partial<Record<BBB, number>>>>;


type Param<T extends RR> = {
    [KA in keyof T & AAA]?: {
        [KB in keyof T[KA] & BBB]?: TestData<Extract<T[KA][KB], number>>
    }
}

class Test<T extends RR> {
    constructor(
        public readonly data: Param<T>
    ) { }
}


new Test(
    {
        [AAA.a1]: {
            [BBB.b1]: {
                components: [1, 2], // 注释后c应变为number而非never
                avaible: (c) => {
                    //    ^?
                }
            },
        },
        [AAA.a2]: {
            [BBB.b2]: {
                components: [5],
                avaible: (c) => {
                   //    ^?
                }
            },
              [BBB.b1]: {
                components: [8],
                avaible: (c) => {
                   //    ^?
                }
            },
        },
    }
);

问题原因

原Param<T>类型中,当传入对象未给某个条目指定components时,对应的T[KA][KB]会被推断为undefined,Extract<T[KA][KB], number>结果为never,导致TestData的泛型参数为never,最终avaible的参数类型变成never。

修复方案

调整Param类型的映射逻辑,增加条件判断处理未定义的情况,确保没有指定字面量类型时回退到number:

enum AAA {
    a1 = 'a1', a2 = 'a2', a3 = 'a3',
}
enum BBB {
    b1 = 'b1', b2 = 'b2', b3 = 'b3',
}

type TestData<T extends number = number> = {
    components?: T[];
    avaible: (c: T) => void; 
}

type RR = Partial<Record<AAA, Partial<Record<BBB, number>>>>;

// 调整Param类型,支持未定义条目回退到number
type Param<T extends RR> = {
    [KA in keyof T & AAA]?: {
        // 处理已在T中定义的BBB键
        [KB in keyof T[KA] & BBB]?: 
            T[KA][KB] extends number 
                ? TestData<T[KA][KB]> 
                : TestData<number>
    } & {
        // 处理未在T中定义的BBB键,直接使用number类型
        [KB in Exclude<BBB, keyof T[KA]>]?: TestData<number>
    }
}

class Test<T extends RR> {
    constructor(
        public readonly data: Param<T>
    ) { }
}

new Test(
    {
        [AAA.a1]: {
            [BBB.b1]: {
                // components: [1, 2], // 注释后c类型为number
                avaible: (c) => {
                    //    ^? 类型为number
                }
            },
        },
        [AAA.a2]: {
            [BBB.b2]: {
                components: [5],
                avaible: (c) => {
                   //    ^? 类型为5
                }
            },
            [BBB.b1]: {
                components: [8],
                avaible: (c) => {
                   //    ^? 类型为8
                }
            },
        },
    }
);

修复说明

  1. 对T[KA][KB]增加条件判断:如果是number类型则使用对应的字面量类型,否则回退到TestData<number>
  2. 新增Exclude<BBB, keyof T[KA]>的映射,确保未在T中定义的BBB枚举键也能默认使用number类型的TestData
  3. 保留了原有components存在时的字面量类型推断,同时解决了未提供components时类型回退的问题

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 23:22:34