打字稿有条件地使 属性 可选
Typescript conditionally making a property optional
假设我有一个类型
interface Definition {
[key: string]: {
optional: boolean;
}
}
现在是否可以构造一个类型ValueType<T extends Definition>
,对于定义
{
foo: { optional: true },
bar: { optional: false }
}
输出类型
{
foo?: string;
bar: string;
}
这可能吗?
我的第一个方法是一个由映射类型和 Omit
组成的构造,它通过将可选属性和必需属性合并到一个对象中来工作。但是,这需要一个由所有可选键组成的联合类型,我不知道该怎么做。
基本想法是:
type ValueType<T extends Definition> =
{ [key in keyof T]?: string }
& Omit<{ [key in keyof T]: string }, OptionalKeys<T>>
OptionalKeys<T>
返回由所有可选键构成的上述联合类型。
您可以通过以下逻辑获得该行为:
type ValueType<T extends Record<string, { optional: boolean }>> =
(
{ [K in keyof T]?: string } &
{ [K in keyof T as T[K]["optional"] extends false ? K : never]-?: string }
) extends infer O ? { [K in keyof O]: O[K] } : never
我们创建了 optional
是 true
和 ?
的所有键以及 optional
是 false
的所有键的交集。末尾的 extends infer O ? {[K in keyof O]: O[K]} : never
使类型“更漂亮”,但在功能上无关紧要。
编辑:
感谢@jcalz。我们可以把它缩短一点,同时保持键的顺序。
假设我有一个类型
interface Definition {
[key: string]: {
optional: boolean;
}
}
现在是否可以构造一个类型ValueType<T extends Definition>
,对于定义
{
foo: { optional: true },
bar: { optional: false }
}
输出类型
{
foo?: string;
bar: string;
}
这可能吗?
我的第一个方法是一个由映射类型和 Omit
组成的构造,它通过将可选属性和必需属性合并到一个对象中来工作。但是,这需要一个由所有可选键组成的联合类型,我不知道该怎么做。
基本想法是:
type ValueType<T extends Definition> =
{ [key in keyof T]?: string }
& Omit<{ [key in keyof T]: string }, OptionalKeys<T>>
OptionalKeys<T>
返回由所有可选键构成的上述联合类型。
您可以通过以下逻辑获得该行为:
type ValueType<T extends Record<string, { optional: boolean }>> =
(
{ [K in keyof T]?: string } &
{ [K in keyof T as T[K]["optional"] extends false ? K : never]-?: string }
) extends infer O ? { [K in keyof O]: O[K] } : never
我们创建了 optional
是 true
和 ?
的所有键以及 optional
是 false
的所有键的交集。末尾的 extends infer O ? {[K in keyof O]: O[K]} : never
使类型“更漂亮”,但在功能上无关紧要。
编辑:
感谢@jcalz。我们可以把它缩短一点,同时保持键的顺序。