如何为TypeScript中键值类型各异的Map添加精确类型定义?
为键值类型一一对应的Map实现自动类型推断
问题背景
我有一个Map,每个键对应不同类型的值,示例代码如下:
const m = new Map() map.set(LE_CONST_NAMES, {names: ['jhon', 'pietro']}) map.set(LE_CONST_MAMA, ['unbelievable', 'yes', {who: 'are'}]) map.set(LE_CONST_OTHER, {status: 'no status'})
这些值的类型各不相同,当前取值时必须手动添加类型断言:
type Name = {names: string[]} type Status = {status: 'no status' | 'maybe status'} const names = map.get(LE_CONST_NAMES) as Name const theOthers = map.get(LE_CONST_OTHER) as Status
我尝试过给Map指定联合类型值:
const m = new Map<string, Name | Status | Mama | AllTheOther40SOmethingTypes>()
但这样get返回的仍是联合类型,无法自动推断对应键的具体类型,必须手动断言。我希望自定义Map类型,让调用get时能自动识别对应类型,比如:
const names = map.get(LE_CONST_NAMES) // 自动识别为Name类型 const theOthers = map.get(LE_CONST_OTHER) // 自动识别为Status类型
解决方案
1. 定义键值映射关系
首先把所有常量键与对应值的类型整理成一个映射类型,明确每个键对应的值类型:
// 先定义各个值的具体类型 type Name = { names: string[] }; type Mama = (string | { who: string })[]; type Status = { status: 'no status' | 'maybe status' }; // 定义键到值的映射,把所有40多个键值对都补充在这里 type MapKeyToValue = { [LE_CONST_NAMES]: Name; [LE_CONST_MAMA]: Mama; [LE_CONST_OTHER]: Status; };
2. 自定义带类型推断的Map接口
基于原生Map类型,重写get方法,让它根据传入的键自动返回对应类型:
type TypedMap = Omit<Map<keyof MapKeyToValue, MapKeyToValue[keyof MapKeyToValue]>, 'get'> & { get: <Key extends keyof MapKeyToValue>(key: Key) => MapKeyToValue[Key] | undefined; };
3. 创建带类型约束的Map实例
创建Map时断言为自定义的TypedMap类型,后续的set和get操作都会自动做类型校验和推断:
const m = new Map() as TypedMap; // 设置值时会校验类型,不符合会报错 m.set(LE_CONST_NAMES, { names: ['jhon', 'pietro'] }); m.set(LE_CONST_MAMA, ['unbelievable', 'yes', { who: 'are' }]); m.set(LE_CONST_OTHER, { status: 'maybe status' }); // 取值自动推断类型,无需手动断言 const names = m.get(LE_CONST_NAMES); // 类型为 Name | undefined const mama = m.get(LE_CONST_MAMA); // 类型为 Mama | undefined const status = m.get(LE_CONST_OTHER); // 类型为 Status | undefined
可选:实现严格类型(无undefined)
如果能保证所有键都会被提前初始化,不需要处理undefined的情况,可以修改自定义Map类型:
type StrictTypedMap = Omit<Map<keyof MapKeyToValue, MapKeyToValue[keyof MapKeyToValue]>, 'get'> & { get: <Key extends keyof MapKeyToValue>(key: Key) => MapKeyToValue[Key]; }; // 初始化时传入所有键值对,确保无缺失 const m = new Map([ [LE_CONST_NAMES, { names: ['jhon', 'pietro'] }], [LE_CONST_MAMA, ['unbelievable', 'yes', { who: 'are' }]], [LE_CONST_OTHER, { status: 'no status' }], ]) as StrictTypedMap; const names = m.get(LE_CONST_NAMES); // 类型直接为 Name
内容的提问来源于stack exchange,提问作者Lucas Steffen
相关产品推荐
相关产品推荐

