如何将Partial类型对象安全转为非Partial类型?TypeScript技术问题
安全将嵌套Partial类型转换为原类型的TypeScript方案
首先定义原类型Person和嵌套的PartialPerson类型:
type Person = { name: { first: string, last: string; }, age: number }; type PartialPerson = Partial<{ name: Partial<{ first: string, last: string; }>, age: number }>;
现有一个已填充所有属性的PartialPerson实例:
const completePartialPerson: PartialPerson = { name: { first: 'joe', last: 'bloggs', }, age: 45 };
需要将它传入要求Person类型参数的函数:
function addPerson(person: Person){} // 直接传入会触发类型错误 addPerson(completePartialPerson);
错误提示如下:
Argument of type 'Partial<{ name: Partial<{ first: string; last: string; }>; age: number; }>' is not assignable to parameter of type 'Person'. Types of property 'name' are incompatible. Type 'Partial<{ first: string; last: string; }>' is not assignable to type '{ first: string; last: string; }'. Property 'first' is optional in type 'Partial<{ first: string; last: string; }>' but required in type '{ first: string; last: string; }'.(2345)
直接用as断言虽然能解决,但会丢失类型安全性——比如后续修改Person的name字段为name2时,不会触发任何错误提示。
安全转换方案
1. 带运行时检查的类型守卫函数
通过编写类型守卫,在运行时验证对象结构是否符合Person类型,同时保留编译时的类型检查:
function isPerson(obj: unknown): obj is Person { if (typeof obj !== 'object' || obj === null) return false; const person = obj as Person; return ( typeof person.name === 'object' && person.name !== null && typeof person.name.first === 'string' && typeof person.name.last === 'string' && typeof person.age === 'number' ); } // 使用方式 if (isPerson(completePartialPerson)) { addPerson(completePartialPerson); // 此处类型安全,编译时会检查类型匹配 } else { // 处理不符合结构的情况 throw new Error('对象不符合Person类型结构'); }
这种方式既保证了编译时的类型安全,又在运行时做了结构校验,避免非法数据传入函数。
2. 编译时的严格类型断言函数
如果确定运行时数据一定符合Person结构,但希望保留编译时的类型关联,可以编写带类型约束的断言函数:
function assertIsPerson(obj: unknown): asserts obj is Person { if (!isPerson(obj)) { throw new Error('对象不符合Person类型结构'); } } // 使用方式 assertIsPerson(completePartialPerson); addPerson(completePartialPerson); // 此时类型已被断言为Person,且编译时会检查类型匹配
这种方式在编译时会保持Person类型的关联,比如修改Person的字段名时,断言函数会触发类型错误,提醒你更新校验逻辑,避免了as断言的无约束问题。
内容的提问来源于stack exchange,提问作者wlf
相关产品推荐
相关产品推荐

