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

如何让TypeScript类型系统感知Partial<T>的属性填充状态?

实现逐步填充Partial时的类型细化

泛型函数实现自动类型细化

通过泛型捕获传入对象的具体类型,结合交叉类型将指定属性转为必填,同时保留其他属性的原有可选/必填状态,完美适配缓存复用场景。

代码实现

type PartialUserInfo = {
  name?: string;
  age?: number;
  shoeBrand?: string;
};

// 辅助类型:把指定属性转为必填,保留其他属性的原有状态
type FillRequired<T, K extends keyof T> = T & { [P in K]-?: T[P] };

// 填充用户名的函数
function fillInUserName<T extends PartialUserInfo>(
  id: string,
  info: T
): FillRequired<T, 'name'> {
  if (info.name == undefined) {
    info.name = lookUpUserName(id); // 假设lookUpUserName是已实现的查询函数
  }
  return info as FillRequired<T, 'name'>;
}

// 填充鞋品牌的函数
function fillInShoeBrand<T extends PartialUserInfo>(
  id: string,
  info: T
): FillRequired<T, 'shoeBrand'> {
  if (info.shoeBrand == undefined) {
    info.shoeBrand = lookUpShoeBrand(id);
  }
  return info as FillRequired<T, 'shoeBrand'>;
}

// 使用示例
function doSomeUserStuff(userId: string, info: PartialUserInfo) {
  // 此时info.name 是 string | undefined,直接访问length会报错(符合预期)
  // console.log(info.name.length); 

  info = fillInUserName(userId, info);
  // 类型系统自动识别info.name已为string,可安全访问
  console.log(info.name.length);

  info = fillInShoeBrand(userId, info);
  // name和shoeBrand均已转为必填,可直接访问
  console.log(info.name.length, info.shoeBrand.length);
}

核心原理

  • 泛型T会精准捕获传入info的实际类型(比如如果传入的info已经包含必填的age,T会保留这个信息)
  • FillRequired类型通过交叉类型,用-?移除指定属性的可选修饰符,同时保留其他属性的原有状态

断言函数方案(无需重新赋值)

如果不想通过返回值重新赋值,可以用断言函数直接修改原对象并告知类型系统属性已填充:

// 断言用户名已填充
function assertUserNameFilled(
  id: string,
  info: PartialUserInfo
): asserts info is FillRequired<PartialUserInfo, 'name'> {
  if (info.name == undefined) {
    info.name = lookUpUserName(id);
  }
}

// 使用示例
function doSomeUserStuff(userId: string, info: PartialUserInfo) {
  // info.name 是 string | undefined,直接访问报错
  // console.log(info.name.length);

  assertUserNameFilled(userId, info);
  // 断言后类型系统自动将info.name转为string
  console.log(info.name.length);
}

通用化填充工具(提升复用性)

如果有大量类似的填充函数,可以封装通用工具函数,避免重复代码:

// 通用填充必填属性的断言函数
function fillRequiredProp<T, K extends keyof T>(
  obj: T,
  prop: K,
  fallback: () => NonNullable<T[K]>
): asserts obj is FillRequired<T, K> {
  if (obj[prop] == undefined) {
    obj[prop] = fallback() as T[K];
  }
}

// 使用方式
fillRequiredProp(info, 'name', () => lookUpUserName(userId));
// 执行后info.name自动转为必填

内容的提问来源于stack exchange,提问作者Ipsquiggle

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 23:20:56