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

如何基于TypeScript的State类型将嵌套属性four设为必填?

问题

我定义了如下TypeScript类型:

type State = {
  one?: string;
  two?: {
    three?: {
      four?: string;
      five?: string;
      six: number
    },
    seven: string
  }
}

我希望复用State类型生成一个新类型,仅将嵌套属性four设为必填,其余属性保持原状态。我知道Required工具类型,但不确定如何应用到深层嵌套属性上。

背景:我有一个State[]类型的数组,需要通过filter和map筛选出包含有效four属性(某ID)的元素,代码如下:

const states: State[] = [...];
states
  .filter((state) => state.two?.three?.four && valid(state.two?.three?.four))
  .map((state) => mapFour(state.two.three.four))

但TypeScript编译器报错,提示state.two.three.four可能为undefined——这是因为类型收窄无法跨filter和map作用域生效。因此我需要编写显式类型守卫(形如.filter((state):state is MyNewTypeWhereFourIsNotOptional => ...)),所以必须创建这个将深层嵌套属性设为必填的新类型。

解决方案

方案1:手动复用原类型定义新类型

针对当前State的结构,可以直接嵌套定义新类型,复用原类型的属性类型避免重复代码:

type StateWithRequiredFour = {
  // 保持原属性的可选状态
  one?: State['one'];
  // two设为必填,否则无法访问后续嵌套属性
  two: {
    // three设为必填,同理
    three: {
      // four设为必填
      four: string;
      // 保持原属性的可选状态
      five?: State['two']['three']['five'];
      // six原本就是必填,直接复用类型
      six: State['two']['three']['six'];
    };
    // seven原本就是必填,复用类型
    seven: State['two']['seven'];
  };
};

方案2:通用深层必填工具类型

如果需要频繁处理深层属性的必填转换,可以编写一个通用工具类型RequiredDeepPath,支持通过路径字符串指定要设为必填的深层属性:

type RequiredDeepPath<T, Path extends string> = 
  // 拆分路径为当前层级和剩余路径
  Path extends `${infer First}.${infer Rest}`
    ? T extends object
      ? {
          [K in keyof T]: 
            // 如果当前键是路径的第一部分,递归处理剩余路径并将当前层级设为必填
            K extends First ? RequiredDeepPath<Required<T[K]>, Rest> : T[K]
        }
      : T
    // 路径是单个键的情况,仅将该键设为必填
    : T extends object ? Required<Pick<T, Path & keyof T>> & Omit<T, Path & keyof T> : T;

// 应用到State类型,指定路径'two.three.four'
type StateWithRequiredFour = RequiredDeepPath<State, 'two.three.four'>;

编写类型守卫并使用

有了新类型后,编写对应的类型守卫函数:

const hasValidFour = (state: State): state is StateWithRequiredFour => {
  // 验证four存在且有效
  return !!state.two?.three?.four && valid(state.two.three.four);
};

修改数组处理代码,使用带类型守卫的filter:

states
  .filter(hasValidFour)
  .map((state) => mapFour(state.two.three.four)) // 此处编译器不再报错

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 07:47:22