TypeScript:根据另一属性值推断对应属性类型
TypeScript类型安全的订单属性更新方案
问题场景
现有如下TypeScript代码定义了订单、客户、地址相关接口,以及用于更新订单属性的请求接口:
interface Order { customer: Customer, address: Address } interface Customer { name: string } interface Address { firstLine: string } interface OrderUpdateRequest { key: 'customer'|'address', value: Customer | Address } const myThing = {customer: {name: 'Bob'}, address: {firstLine: 'my street'}} as Order const updateRequest = {key:'customer', value: {name : 'Dave'}} as OrderUpdateRequest myThing[updateRequest['key']] = updateRequest['value']
执行上述代码时会出现以下类型错误:
Type 'Customer | Address' is not assignable to type 'Customer & Address'. Type 'Customer' is not assignable to type 'Customer & Address'. Property 'firstLine' is missing in type 'Customer' but required in type 'Address'.(2322) input.tsx(11, 5): 'firstLine' is declared here.
错误原因
原OrderUpdateRequest接口中,key和value是独立的联合类型,TypeScript无法建立两者的关联关系。当执行赋值操作时,TS会假设updateRequest.key可能是customer或address中的任意一个,因此要求value必须同时兼容Customer和Address类型(即交叉类型Customer & Address),但实际传入的value只符合其中一种类型,导致类型不匹配。
解决方案
通过泛型接口将key和value的类型绑定,确保当key指定为Order的某个属性名时,value的类型自动匹配该属性对应的类型。
修改后的代码实现
interface Order { customer: Customer, address: Address } interface Customer { name: string } interface Address { firstLine: string } // 泛型请求接口,K约束为Order的键类型 interface OrderUpdateRequest<K extends keyof Order> { key: K, value: Order[K] } const myThing = {customer: {name: 'Bob'}, address: {firstLine: 'my street'}} as Order // 泛型函数处理更新,确保类型安全 function updateOrder<K extends keyof Order>(order: Order, request: OrderUpdateRequest<K>) { order[request.key] = request.value } // 调用示例:key为'customer'时,value必须是Customer类型 updateOrder(myThing, {key: 'customer', value: {name: 'Dave'}}) // 调用示例:key为'address'时,value必须是Address类型 updateOrder(myThing, {key: 'address', value: {firstLine: 'new street'}})
直接使用泛型请求对象的写法
如果不需要封装函数,也可以直接通过泛型参数指定类型:
const customerUpdate: OrderUpdateRequest<'customer'> = {key: 'customer', value: {name: 'Dave'}} myThing[customerUpdate.key] = customerUpdate.value const addressUpdate: OrderUpdateRequest<'address'> = {key: 'address', value: {firstLine: 'new street'}} myThing[addressUpdate.key] = addressUpdate.value
效果说明
修改后:
- 当
key为'customer'时,TypeScript会自动校验value必须符合Customer类型 - 当
key为'address'时,TypeScript会自动校验value必须符合Address类型 - 若传入不匹配的
key和value,会立即触发类型错误,实现类型安全的属性更新
内容的提问来源于stack exchange,提问作者Chris A
相关产品推荐
相关产品推荐

