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

TypeScript类型重映射时如何保留可选属性模式?

解决TypeScript类型重映射时保留可选属性的问题

问题分析

你的PrefixAll类型工具在给接口属性添加前缀时,会丢失原属性的可选性——所有属性都变成了必填项。这是因为TypeScript使用as进行键重映射时,不会自动将原属性的可选修饰符(?)关联到新生成的属性上,必须手动处理才能保留原有属性的可选状态。

解决方案

我们可以通过分离必填/可选属性分别处理,再合并结果的方式解决这个问题:

  1. 先定义工具类型提取接口中的所有可选属性键
  2. 修改PrefixAll类型,分别对必填、可选属性添加前缀,最后合并两种结果

完整代码实现

// 提取接口中的可选属性键
type OptionalKeys<T> = {
    [K in keyof T]-?: {} extends Pick<T, K> ? K : never;
}[keyof T];

/** 为属性添加前缀并大写属性首字母,同时保留原属性的可选状态 */
type PrefixAll<T, P extends string> = 
    // 处理必填属性:保持必填状态
    { [K in Exclude<keyof T, OptionalKeys<T>> & string as `${P}${Capitalize<K>}`]: T[K] } &
    // 处理可选属性:保留可选状态
    { [K in OptionalKeys<T> & string as `${P}${Capitalize<K>}`]?: T[K] };

使用示例

import type { ReactNode, CSSProperties } from 'react';

interface ChildrenProps {
    children: ReactNode;
    className?: string;
    style?: CSSProperties;
}

// 生成带前缀的新类型
type ChildrenPropsWithPrefix = PrefixAll<ChildrenProps, 'child'>;

生成的ChildrenPropsWithPrefix类型与期望完全一致:

interface ChildrenPropsWithPrefix {
    childChildren: ReactNode;
    childClassName?: string;
    childStyle?: CSSProperties;
}

原理说明

  • OptionalKeys<T>:通过Pick<T, K>判断单个属性是否可选——如果空对象{}可以赋值给Pick<T, K>,说明该属性是可选的(可选属性允许未定义)。
  • PrefixAll类型中,先用Exclude分离出必填属性,直接生成带前缀的必填属性;再对可选属性生成带前缀的可选属性,最后通过交叉类型合并两者,既满足前缀和首字母大写的要求,也完整保留了原属性的可选状态。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 21:36:26