You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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>类型,意味着它的所有属性都是可选的,类型为原属性类型 | undefined
  • user[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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 20:00:35