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

React TypeScript实现移除defaultProps属性undefined的工具类型

TLDR;

现有写法不生效的原因

你的实现失效核心是两个TypeScript映射类型的固有特性:

  • 同态映射类型(即直接通过[p in keyof Props]遍历源类型键的映射)会默认继承源类型的属性修饰符,包括可选修饰符?、只读修饰符readonly。
  • 可选属性包含两层语义:1. 属性可以缺省;2. 属性值类型自动包含undefined。你仅通过Exclude移除了值类型中显式声明的undefined,但没有移除属性本身的可选修饰符,TS会因为可选标记自动给值类型追加undefined,同时保留属性可缺省的特性,因此最终推导结果不符合预期。

正确实现

你需要将Props拆分为两部分分别处理,再通过交叉类型合并:

  1. 不在defaultProps键范围内的属性:完全保留原类型的可选/必填状态、值类型
  2. 在defaultProps键范围内的属性:移除可选修饰符,同时排除值类型中的undefined

完整实现代码:

type RespectDefaultProps<Props, DefaultProps> = 
  // 保留所有未被defaultProps覆盖的属性
  Omit<Props, keyof DefaultProps> 
  & {
    // 仅处理同时存在于Props中的defaultProps键,移除可选修饰符,排除undefined类型
    [K in keyof DefaultProps as K extends keyof Props ? K : never]-?: Exclude<Props[K], undefined>
  };

效果验证

用你提供的测试用例验证:

type testRespectDefaultProps = RespectDefaultProps<{ name?: string; age?: number }, { age: number }>;
// 推导结果等价于:
// {
//   name?: string | undefined;
//   age: number;
// }

完全符合预期,在React组件场景下可以直接使用:

interface CompProps {
  name?: string;
  age?: number;
}

const CompDefaultProps = {
  age: 25,
};

const Comp: React.FC<CompProps> = (_props) => {
  const props = _props as RespectDefaultProps<CompProps, typeof CompDefaultProps>
  props.age // 推导为number,无undefined类型
  return <></>
};

Comp.defaultProps = CompDefaultProps

补充说明

  • 实现中-?是TS映射类型的修饰符操作语法,作用是移除对应键的可选标记,将属性转为必填
  • as K extends keyof Props ? K : never是键重映射语法,会自动过滤DefaultProps中不存在于Props定义的冗余键,避免生成无效的属性定义,兼容极端场景下的类型安全。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 04:06:20