TypeScript 实现关联对象属性的带默认值可选参数类型定义
TypeScript 实现带默认键值的灵活通用取值函数
原有方案的核心痛点
我们在实现通用对象取值函数时,先后尝试的三个版本都存在不同问题:
- 基础版
getVal:必须显式传入对象键名,无法实现"默认取id属性"的便捷逻辑 - 带默认值的问题版
getValBad:直接给key参数设置默认值"id",TS会抛出类型错误——因为泛型T没有任何约束,TS无法保证任意传入的对象一定存在id键,"id"不属于keyof T的合法取值 - 强制约束版
getValOk:给泛型加T extends {id: any}的约束虽然能解决类型报错,但灵活性太差——哪怕用户根本不需要用到id的默认值,只要传入的对象没有id属性,就会触发类型错误,不符合通用工具函数的定位。
满足全部校验规则的实现方案
核心思路是利用 TypeScript 函数重载 分离两种调用场景的类型约束:
- 当用户不传key参数时:单独给这个场景加约束,要求传入的对象必须存在
id属性,此时默认取对象的id值 - 当用户显式传入key参数时:取消对象必须带id的强制约束,只要求传入的key是当前对象的合法键名即可
最终的getValGood实现代码:
// 重载1:匹配无key参数的调用场景,强制对象必须包含id属性 function getValGood<T extends { id: unknown }>(obj: T): T["id"]; // 重载2:匹配显式传key的调用场景,无额外结构约束 function getValGood<T>(obj: T, key: keyof T): T[keyof T]; // 内部实现 function getValGood<T>(obj: T, key: keyof T = "id" as keyof T) { return obj[key]; }
注意:实现层的
"id" as keyof T是安全的类型断言,因为所有外部调用的路径都已经被重载签名约束:只有当对象存在id属性时,才会走到默认值的执行逻辑,不存在键值不匹配的运行时风险。
校验规则验证
我们可以对照需求逐一验证类型检查的表现:
- 传入带id属性的对象且不传key:
调用会匹配第一个重载,对象结构满足getValGood({id: 1}) // 正常通过检查,返回值类型为number{id: unknown}的约束,没有类型问题。 - 传入仅含大写ID属性的对象且显式指定key为"ID":
调用会匹配第二个重载,没有强制要求对象带小写id属性,传入的"ID"是对象的合法键,检查通过。getValGood({ID: 1}, "ID") // 正常通过检查,返回值类型为number - 传入仅含大写ID属性的对象且不传key:
调用会优先匹配第一个重载,但传入的对象不满足getValGood({ID: 1}) // 触发类型报错{id: unknown}的结构约束,TS会直接抛出类型错误,完全符合预期。
内容的提问来源于stack exchange,提问作者Jason Siefken
相关产品推荐
相关产品推荐

