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

如何为基于枚举映射的TypeScript结果声明类型?

问题描述

我有两个TypeScript枚举和一个映射常量:

enum FirstEnum {
    firstEnumKey1 = 'firstEnumKey1',
    firstEnumKey2 = 'firstEnumKey2',
    firstEnumKey3 = 'firstEnumKey3',
    firstEnumKey4 = 'firstEnumKey4',
}

enum SecondEnum {
    secondEnumKey1 = 'secondEnumKey1',
    secondEnumKey2 = 'secondEnumKey2',
    secondEnumKey3 = 'secondEnumKey3',
}

// 映射FirstEnum到SecondEnum数组
const map: {[i in FirstEnum]: SecondEnum[] } = {
    'firstEnumKey1': [SecondEnum.secondEnumKey1],
    'firstEnumKey2': [],
    'firstEnumKey3': [SecondEnum.secondEnumKey2, SecondEnum.secondEnumKey3],
    'firstEnumKey4': [SecondEnum.secondEnumKey2, SecondEnum.secondEnumKey3],
};

我需要基于这个map定义一组数据,每个SecondEnum成员对应一个对象,对象的键是map中值数组包含该SecondEnum成员的FirstEnum成员,结构示例如下:

const getSecondEnumValuesBasedOnMap = {
    [SecondEnum.secondEnumKey1]: {
        [FirstEnum.firstEnumKey1]: 'some value',
    },
    [SecondEnum.secondEnumKey2]: {
        [FirstEnum.firstEnumKey3]: 'some value',
        [FirstEnum.firstEnumKey4]: 'some value',
    },
    [SecondEnum.secondEnumKey3]: {
        [FirstEnum.firstEnumKey3]: 'some value',
        [FirstEnum.firstEnumKey4]: 'some value',
    },
}

当map发生变更时(比如给FirstEnum.firstEnumKey2的数组添加SecondEnum.secondEnumKey2),这个数据结构需要同步更新。我希望给结果声明一个TypeScript类型,让map变更时,编译器能提示我更新结果。

解决方案

要实现这个需求,我们可以通过TypeScript的条件类型和映射类型推导基于map的强约束类型,具体步骤如下:

1. 让TypeScript精准推导map的类型

首先不要手动指定map的类型,而是用as const让TypeScript推导最窄的字面量类型,这样类型能完全反映map的实际内容:

const map = {
    [FirstEnum.firstEnumKey1]: [SecondEnum.secondEnumKey1],
    [FirstEnum.firstEnumKey2]: [],
    [FirstEnum.firstEnumKey3]: [SecondEnum.secondEnumKey2, SecondEnum.secondEnumKey3],
    [FirstEnum.firstEnumKey4]: [SecondEnum.secondEnumKey2, SecondEnum.secondEnumKey3],
} as const;

2. 定义辅助类型推导映射关系

我们需要两个辅助类型来建立SecondEnum到FirstEnum的反向映射:

// 提取map的具体类型
type MapType = typeof map;

// 推导每个SecondEnum成员对应的FirstEnum成员集合
type SecondToFirstMap = {
    [S in SecondEnum]: {
        // 遍历所有FirstEnum成员,判断当前S是否在其对应的SecondEnum数组中
        [F in keyof MapType]: S extends MapType[F][number] ? F : never
    }[keyof MapType] // 过滤掉never类型,只保留符合条件的FirstEnum成员
};

3. 定义最终结果类型

基于SecondToFirstMap生成最终的结果类型,约束每个SecondEnum对应的对象结构:

// 这里的string可以替换成你实际需要的值类型
type ResultType = {
    [S in SecondEnum]: {
        [F in SecondToFirstMap[S]]: string;
    }
};

4. 用ResultType约束数据对象

现在用ResultType来声明你的数据对象,编译器会自动校验结构是否符合map的映射关系:

const getSecondEnumValuesBasedOnMap: ResultType = {
    [SecondEnum.secondEnumKey1]: {
        [FirstEnum.firstEnumKey1]: 'some value',
    },
    [SecondEnum.secondEnumKey2]: {
        [FirstEnum.firstEnumKey3]: 'some value',
        [FirstEnum.firstEnumKey4]: 'some value',
    },
    [SecondEnum.secondEnumKey3]: {
        [FirstEnum.firstEnumKey3]: 'some value',
        [FirstEnum.firstEnumKey4]: 'some value',
    },
};

验证效果

当你修改map的内容时,比如给FirstEnum.firstEnumKey2添加SecondEnum.secondEnumKey2:

const map = {
    [FirstEnum.firstEnumKey1]: [SecondEnum.secondEnumKey1],
    [FirstEnum.firstEnumKey2]: [SecondEnum.secondEnumKey2], // 新增映射
    [FirstEnum.firstEnumKey3]: [SecondEnum.secondEnumKey2, SecondEnum.secondEnumKey3],
    [FirstEnum.firstEnumKey4]: [SecondEnum.secondEnumKey2, SecondEnum.secondEnumKey3],
} as const;

此时TypeScript编译器会立即提示getSecondEnumValuesBasedOnMap中的secondEnumKey2对象缺少firstEnumKey2键,强制你同步更新数据结构,实现了映射变更后的自动校验。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.17 19:22:53