TypeScript中Partial<User>赋值报错:string|number无法赋值给undefined
TypeScript映射类型练习中的类型错误规范解法请求
我正在学习TypeScript的映射类型,练习时遇到如下错误:
Type 'string | number' is not assignable to type 'undefined'
我理解错误原因,但作为TS新手,不清楚规范的解决方法,且不想使用any这类不严谨的方案,特寻求正确的类型安全解法。
代码示例
// Represents schema of a Db table type User = { id: number; // might be auto incremented by DB name: string; // contains textual name data }; // Manual work. Define a type that represents schema of "User" and add some metadata type DBFields = { id: { format: "incrementing" }; name: { type: string; pii: true }; }; type ExtractPII<Type> = { [Property in keyof Type]: Type[Property] extends { pii: true } ? true : false; }; type ObjectsNeedingGDPRDeletion = ExtractPII<DBFields>; // Manual work. Create object of ObjectsNeedingGDPRDeletion type let deletionMarkers: ObjectsNeedingGDPRDeletion = { id: false, name: true }; function handleGDPRDeletionRequest(user: User, deletionMarkers: ObjectsNeedingGDPRDeletion) { let cleanedUser: Partial<User> = {}; for (const field of Object.keys(user)) { if (!deletionMarkers[field as keyof User]) { cleanedUser[field as keyof User] = user[field as keyof User]; // 错误发生在此行 } } console.log(cleanedUser); // Prints: { id: 1 } } let user = { id: 1, name: "John Doe", }; handleGDPRDeletionRequest(user, deletionMarkers); // { id: 1 }
错误原因分析
错误出现在cleanedUser[field as keyof User] = user[field as keyof User];这一行:
cleanedUser被声明为Partial<User>类型,意味着它的所有属性都是可选的,类型为原属性类型 | undefineduser[field as keyof User]的类型是string | number,直接赋值给Partial<User>的属性时,TypeScript会因为类型不兼容抛出错误。
规范解决方法
这里有几种类型安全的解决方式:
方法1:泛型辅助函数确保类型匹配
通过泛型函数明确每次赋值的属性类型,避免宽泛的联合类型冲突:
function handleGDPRDeletionRequest(user: User, deletionMarkers: ObjectsNeedingGDPRDeletion) { let cleanedUser: Partial<User> = {}; // 泛型函数处理属性赋值,确保类型一致 function assignField<K extends keyof User>(key: K) { cleanedUser[key] = user[key]; } for (const field of Object.keys(user) as Array<keyof User>) { if (!deletionMarkers[field]) { assignField(field); } } console.log(cleanedUser); }
泛型函数assignField会根据传入的key推断出具体属性类型,让TypeScript确认赋值操作的类型安全性。
方法2:先操作完整类型对象再转换
先使用完整类型的临时对象处理属性删除,再转换为Partial<User>:
function handleGDPRDeletionRequest(user: User, deletionMarkers: ObjectsNeedingGDPRDeletion) { let tempUser: Record<keyof User, User[keyof User]> = { ...user }; for (const field of Object.keys(user) as Array<keyof User>) { if (deletionMarkers[field]) { delete tempUser[field]; } } const cleanedUser: Partial<User> = tempUser; console.log(cleanedUser); }
这种方式避开了直接给Partial<User>赋值的类型限制,操作完成后再做类型转换,保证全程类型安全。
方法3:自定义映射类型精确约束清理结果
基于ObjectsNeedingGDPRDeletion定义只保留非PII属性的专属类型,让cleanedUser的类型更精确:
// 定义仅保留非PII属性的用户类型 type NonPIIUser<T, M> = { [K in keyof T as M[K] extends false ? K : never]: T[K]; }; function handleGDPRDeletionRequest(user: User, deletionMarkers: ObjectsNeedingGDPRDeletion) { let cleanedUser: Partial<NonPIIUser<User, ObjectsNeedingGDPRDeletion>> = {}; for (const field of Object.keys(user) as Array<keyof User>) { if (!deletionMarkers[field]) { cleanedUser[field as keyof NonPIIUser<User, ObjectsNeedingGDPRDeletion>] = user[field]; } } console.log(cleanedUser); }
自定义类型NonPIIUser会自动过滤需要删除的属性,让cleanedUser的类型完全匹配最终结果,进一步提升代码的类型严谨性。
内容的提问来源于stack exchange,提问作者Ash K
相关产品推荐
相关产品推荐

