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

如何声明TypeScript类型以确保其为另一类型的可赋值子集

解决TypeScript merge函数的严格类型约束问题

先明确你遇到的核心问题:

  • 用Partial<T>的写法会错误允许给必填字段传undefined,比如merge(human, {Name: undefined})会被放行
  • 第二种写法存在语法错误,T extends U不能直接作为参数类型使用

要实现你预期的约束规则——必填字段只能传有效值、可选字段可传有效值或undefined、禁止传入原类型以外的字段——我们需要自定义更严格的Partial类型:

// 辅助类型:提取T中的所有必填字段名
type RequiredKeys<T> = { [K in keyof T]-?: {} extends Pick<T, K> ? never : K }[keyof T];
// 辅助类型:提取T中的所有可选字段名
type OptionalKeys<T> = Exclude<keyof T, RequiredKeys<T>>;

// 定义严格的Partial类型:
// - 必填字段只能传原类型(排除undefined)
// - 可选字段可传原类型或undefined
// - 仅允许传入T中存在的字段
type StrictMergePartial<T> = Partial<{
  [K in keyof T]: K extends RequiredKeys<T> 
    ? Exclude<T[K], undefined>
    : T[K] | undefined
}>;

// 最终的merge函数
const merge = <T>(full: T, partial: StrictMergePartial<T>): T => ({
  ...full,
  ...partial
});

// 测试用例验证
interface Person {
  Name: string;
  Age: number;
  Occupation?: string;
}

const human: Person = {
  Name: "John",
  Age: 35,
};

merge(human, { Age: 5 });                  // ✓ 正常通过
merge(human, { Name: "Marc" });            // ✓ 正常通过
merge(human, { Name: undefined });         // ❌ 报错:undefined无法赋值给string类型
merge(human, { Occupation: "Fishermen" }); // ✓ 正常通过
merge(human, { Occupation: undefined });   // ✓ 正常通过
merge(human, { Beer: 5 });                 // ❌ 报错:存在未知字段Beer

类型逻辑说明:

  1. RequiredKeys<T>:通过判断字段是否可从类型中移除,精准提取所有必填字段的名称
  2. StrictMergePartial<T>:针对必填字段排除undefined类型,确保传入值有效;对可选字段保留undefined支持;最后用Partial让所有字段变为可选(符合部分更新的场景)
  3. 函数返回值仍为T,保证合并后的结果完全符合原类型结构

这样就能完全匹配你预期的所有测试用例要求了。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 20:10:30