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

如何在TypeScript中将可选字段转为必填且保留原类型?

问题描述

我定义了如下类型:

type SomeType = {
  hello?: string | undefined;
  world: number;
  meow?: string;
};

希望将其转换为:

type SomeTypeExplicit = {
  hello: string | undefined;
  world: number;
  meow: string;
};

我的需求是通过这个转换后的类型,在组件中强制“所有可选属性必须有默认值”的规则——即使默认值是undefined。

但现有方案都无法满足需求:

  • 使用Required<SomeType>会得到过于严格的结果,直接移除了undefined类型:
    type SomeTypeRequired = {
      hello: string;
      world: number;
      meow: string;
    };
    
  • 使用“Required but possibly undefined type”的方案又过于宽松,给所有原本没有undefined的可选属性也加上了undefined:
    type SomeTypeLooseRequired = {
      hello: string | undefined;
      world: number;
      meow: string | undefined;
    };
    

请问如何创建泛型实现从SomeType到SomeTypeExplicit的转换?

解决方案

在TypeScript中,可选属性的类型会自动包含undefined,所以meow?: string和meow?: string | undefined在类型系统中是等价的。要实现你的需求,需要区分“允许undefined的可选属性”和“不允许undefined的可选属性”,以下是两种可行方案:

方案一:手动指定保留undefined的属性

创建一个泛型,接受原始类型和需要保留undefined的属性列表,对指定属性保留原有类型,对其他可选属性移除undefined并转为必选:

type ExplicitRequired<T, KeepUndefined extends keyof T = never> = {
  [K in keyof T]-?: K extends KeepUndefined ? T[K] : Exclude<T[K], undefined>;
};

使用示例

type SomeType = {
  hello?: string | undefined;
  world: number;
  meow?: string;
};

// 指定'hello'保留undefined,其他可选属性转为必选且移除undefined
type SomeTypeExplicit = ExplicitRequired<SomeType, 'hello'>;

转换后的类型完全符合需求:

type SomeTypeExplicit = {
  hello: string | undefined;
  world: number;
  meow: string;
};

方案二:显式标记需要保留undefined的属性

如果你希望自动推断,可以通过辅助类型标记需要保留undefined的属性,让泛型识别这些标记并做对应处理:

// 辅助类型,用于标记需要保留undefined的属性
type MarkUndefined<T> = T | undefined;

// 原始类型中用MarkUndefined标记需要保留undefined的属性
type SomeType = {
  hello?: MarkUndefined<string>;
  world: number;
  meow?: string;
};

// 判断属性类型是否是标记过的MarkUndefined
type IsMarkedUndefined<T> = T extends MarkUndefined<infer U> ? true : false;

// 实现转换逻辑的泛型
type ExplicitRequired<T> = {
  [K in keyof T]-?: IsMarkedUndefined<T[K]> extends true ? T[K] : Exclude<T[K], undefined>;
};

// 转换得到目标类型
type SomeTypeExplicit = ExplicitRequired<SomeType>;

这种方式不需要手动指定属性列表,但需要你在原始类型中用MarkUndefined显式标记允许undefined的可选属性。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.01 22:50:56