如何定义匹配常量对象任意值的TypeScript类型?
从常量对象中提取值的字面量类型
给定如下常量:
const beatsByDuration = { q: 1, h: 2, w: 4, 1: 4 / 1, 2: 4 / 2, 4: 4 / 4, 8: 4 / 8, 16: 4 / 16, };
已知以下两种Duration类型等价:
type Duration = 'q' | 'h' | 'w' | '1' | '2' | '4' | '8' | '16'; type Duration = keyof typeof beatsByDuration
需求是定义一个可匹配该对象任意值(1 | 2 | 4 | 0.5 | 0.25)的类型,要求匹配值本身而非宽泛的类型,且对象是常量而非类型。
解决方案
要实现这个需求,核心是让TypeScript保留常量对象的字面量值类型,而非自动拓宽为number类型,具体步骤如下:
- 给常量添加
as const断言,锁定每个值的字面量类型:
const beatsByDuration = { q: 1, h: 2, w: 4, 1: 4 / 1, 2: 4 / 2, 4: 4 / 4, 8: 4 / 8, 16: 4 / 16, } as const;
- 通过索引类型提取所有值的联合字面量类型:
type DurationValue = typeof beatsByDuration[keyof typeof beatsByDuration];
此时DurationValue的类型就是1 | 2 | 4 | 0.5 | 0.25,TypeScript会自动对重复值去重。
特殊情况处理
如果无法修改原常量的定义(比如是外部导入的常量),可以通过条件类型尝试提取值类型,但仅当原常量的类型未被拓宽时有效:
type DurationValue = typeof beatsByDuration extends infer T ? T extends Record<string, infer V> ? V : never : never;
若原常量定义时未加as const,TypeScript已将值类型拓宽为number,则此方式只能得到number类型,因此优先推荐给常量添加as const断言的方案。
内容的提问来源于stack exchange,提问作者Steve Bennett
相关产品推荐
相关产品推荐

