interface ComplexObject {
mandatory: string;
title1?: string;
title2?: string;
}
type GetOptional<T> = {};
type Option = GetOptional<ComplexObject>;
function createApp(option: Option) {
// {title1?: string; title2?: string;}
}
上述的代码我们期望通过
提出接口的所有字段
interface ComplexObject {
mandatory: string;
title1?: string;
title2?: string;
}
type GetOptional<T> = {
[P in keyof T]: T[P];
};
type Option = GetOptional<ComplexObject>;
function createApp(option: Option) {}

上述代码就提出了
interface ComplexObject {
mandatory: string;
title1?: string;
title2?: string;
}
type GetOptional<T> = {
// Capitalize将属性名的第一个首字母大写
[P in keyof T as `get${Capitalize<P & string>}`]: T[P];
};
type Option = GetOptional<ComplexObject>;
function createApp(option: Option) {}

仅保留可选属性
interface ComplexObject {
mandatory: string;
a: number;
title1?: string;
title2?: number;
}
type OptionalKeys<T> = {
[K in keyof T]-?: T extends Record<K, T[K]> ? never : K;
}[keyof T];
type GetOptional<T> = Pick<T, OptionalKeys<T>>;
type Option = GetOptional<ComplexObject>;
function createApp(option: Option) {}

OptionalKeys<T> 通过将每个可能的键K 映射到它们自己或never 上来计算类型T 中的所有可选键。映射键的条件检查是建立在是否每个属性K 在T 中是可选的(即不包含在T extends Record<K, T[K]> 的属性K )GetOptional<T> 用于生成一个新的类型,包含所有指定的属性,关于Pick使用请查看
在 TypeScript 的高级类型操作中,[K in keyof T]-? 表示一个映射类型 (Mapped Type),用于遍历类型T 的所有键K 。这里的目的是产生一个新类型,其中T 的所有属性都是必需的,即没有可选属性,具体来说K in keyof T :对于类型T 中的每个键K -? :这是一个修饰符,用于从属性前移除可选性。这意味着如果T 中的属性K 被标记为可选(属性名称后跟一个问号 ?,比如 title1?),-?会将其转换为必需属性
将保留的可选属性改为必填属性
只需要加上
interface ComplexObject {
mandatory: string;
a: number;
title1?: string;
title2?: number;
}
type OptionalKeys<T> = {
[K in keyof T]-?: T extends Record<K, T[K]> ? never : K;
}[keyof T];
type GetOptional<T> = Pick<T, OptionalKeys<T>>;
type Option = Required<GetOptional<ComplexObject>>;
function createApp(option: Option) {}
