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

如何在对象解构赋值中为...rest保留原对象类型并保持类型安全?

TypeScript中保留原运行时代码的Partial类型安全处理方案

问题场景

在TypeScript开发中,需要编写处理Partial<Record>类型(包含约10个属性)的方法,返回与输入同类型的新记录:部分属性被移除、修改,其余多数保持不变。

简化示例代码

type ABCD = Partial<{ a: number, b: number, c: number, d: number }>;

/** 若a为正数则翻倍并移除b;若为负数则仅移除a */
function f(record: ABCD) {
  const {a, b, ...result} = record;
  if (a !== undefined && a > 0) {
    result.a = a * 2;
    // 类型错误:Property 'a' does not exist on type '{ c?: number | undefined; d?: number | undefined; }'
  } else {
    result.b = b;
    // 类型错误:Property 'b' does not exist on type '{ c?: number | undefined; d?: number | undefined; }'
  }
  return result;
}

现有方案局限

两种常见方案均不满足需求:

  • 移除类型安全:违背类型检查的初衷,不符合要求;
  • 修改运行时代码(如使用delete):但该函数是JS库的TS移植版本,必须保留原运行时代码以便后续同步更新。

解决方案:编译时类型处理(不改动运行时代码)

可以通过类型断言和自定义返回类型在编译期解决类型错误,同时完全保留原运行时代码逻辑。核心思路是先将解构后的result断言为更宽松的类型以允许添加属性,最后返回时约束为正确的类型。

基础实现(保证类型安全且保留原代码)

type ABCD = Partial<{ a: number, b: number, c: number, d: number }>;

/** 若a为正数则翻倍并移除b;若为负数则仅移除a */
function f(record: ABCD): ABCD {
  const {a, b, ...result} = record;
  // 将result断言为Partial<ABCD>,允许添加a/b属性,编译后无额外代码
  const mutableResult = result as Partial<ABCD>;
  
  if (a !== undefined && a > 0) {
    mutableResult.a = a * 2;
  } else {
    mutableResult.b = b;
  }
  
  // 返回时转为原类型,保证类型一致性
  return mutableResult as ABCD;
}

更精确的返回类型(可选)

如果需要更精确的返回类型约束(明确哪些属性会被保留/修改),可以通过条件类型定义返回类型:

type ABCD = Partial<{ a: number, b: number, c: number, d: number }>;

// 定义返回类型:根据输入的a属性情况,返回对应子集类型
type FReturnType<T extends ABCD> = 
  T extends {a: number} 
    ? T['a'] extends number 
      ? T['a'] > 0 extends true 
        ? Omit<T, 'b'> & {a: number} 
        : Omit<T, 'a'> 
      : T 
    : T;

/** 若a为正数则翻倍并移除b;若为负数则仅移除a */
function f<T extends ABCD>(record: T): FReturnType<T> {
  const {a, b, ...result} = record;
  const mutableResult = result as Partial<FReturnType<T>>;
  
  if (a !== undefined && a > 0) {
    mutableResult.a = a * 2 as FReturnType<T>['a'];
  } else {
    mutableResult.b = b as FReturnType<T>['b'];
  }
  
  return mutableResult as FReturnType<T>;
}

注:由于TypeScript静态类型系统无法精确判断运行时的数值正负,上述条件类型是近似约束,但已能满足大部分类型安全场景。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 03:25:29