如何用TypeScript泛型实现嵌套对象可选属性的DeepPick处理默认配置
实现通用泛型
DefaultOptions 处理嵌套对象的可选属性 要实现这个能递归提取嵌套对象所有可选属性并转为必填的泛型DefaultOptions,可以利用TypeScript的条件类型和递归类型完成:
type DefaultOptions<T> = T extends object ? { // 保留原必填属性,递归处理嵌套对象 [K in keyof T as T[K] extends undefined ? never : K]: DefaultOptions<T[K]>; } & { // 将原可选属性转为必填,递归处理嵌套对象(排除undefined) [K in keyof T as T[K] extends undefined ? K : never]-?: DefaultOptions<Exclude<T[K], undefined>>; } extends infer O ? { [K in keyof O]: O[K] } : T;
泛型逻辑说明
- 递归处理对象类型:如果传入的
T是对象类型,进入递归处理;否则直接返回原类型。 - 分离必填与可选属性:
- 原类型中的必填属性(类型不包含
undefined)保持必填状态,同时递归处理其嵌套类型。 - 原类型中的可选属性(类型包含
undefined)通过-?修饰符转为必填,递归处理去掉undefined后的嵌套类型。
- 原类型中的必填属性(类型不包含
- 展开交叉类型:通过
infer O将交叉类型展开为普通对象类型,让最终类型显示更直观。
示例1:多层嵌套可选属性处理
定义原类型Options:
type Options = { a: { b: { c?: { e: number; d?: string; f?: boolean; }; }; }; };
生成的DefaultOptions<Options>类型为:
{ a: { b: { c: { e: number; d?: string; f?: boolean; }; }; }; }
对应默认配置:
const defaultOptions: DefaultOptions<Options> = { a: { b: { c: { e: 123 // e是必填属性,必须提供默认值 // d和f为可选,可按需设置默认值 } } } };
示例2:Lambda配置场景
定义原类型LambdaOptions:
type LambdaOptions = { functionName: string; sentry?: { tracesSampleRate?: number; dsn: string; }; };
生成的DefaultOptions<LambdaOptions>类型为:
{ functionName: string; sentry: { tracesSampleRate: number; dsn: string; }; }
对应默认配置:
const defaultLambdaConfig: DefaultOptions<LambdaOptions> = { functionName: 'default-lambda', sentry: { tracesSampleRate: 0.5, dsn: 'https://example.com/sentry-dsn' } };
与defu工具配合使用
defu会自动合并用户配置与默认配置,优先保留用户提供的值:
import defu from 'defu'; const userConfig: LambdaOptions = { functionName: 'my-lambda', sentry: { dsn: 'https://my-project.com/sentry-dsn' } }; const finalConfig = defu(userConfig, defaultLambdaConfig); // finalConfig.sentry.tracesSampleRate 会自动使用默认值0.5
内容的提问来源于stack exchange,提问作者dror
相关产品推荐
相关产品推荐

