英文:
Make all object properties of a type optional
问题
根据给定的类型 T
,如何使所有属性的类型为 object
变为可选的?
因此,对于以下类型:
interface MyObject {
name: string;
age: number;
favorites: {
color: string
}
}
type MyNewObject = ObjectPropertiesOptional<MyObject>;
它将返回:
interface MyNewObject {
name: string;
age: number;
favorites?: {
color: string
}
}
英文:
Given a type T
how can I make all the properties that are object
optional?
So for a type:
interface MyObject {
name: string;
age: number;
favorites: {
color: string
}
}
type MyNewObject = ObjectPropertiesOptional<MyObject>;
it returns
interface MyNewObject {
name: string;
age: number;
favorites?: {
color: string
}
}
答案1
得分: 4
以下是可能的实现:
type ObjectPropertiesOptional<T> = (
Partial<T> & { [K in keyof T as T[K] extends object ? never : K]: T[K] }
) extends infer O ? { [K in keyof O]: O[K] } : never;
整个实现都被包裹在(
...) extends infer O ? { [K in keyof O]: O[K] } : never
中,这是一个让编译器将相对丑陋的交叉类型(例如{foo: string} & {bar: number}
)转换为单一对象类型(例如{foo: string; bar: number}
)的技巧。这与https://stackoverflow.com/q/57683303/2887218中描述的Expand<T>
相同的技术。
实际实现是将Partial<T>
(使用PartialT
的重映射版本进行交叉,该版本仅包含非object
属性。(通过将键重映射为never
,我们将其抑制)。
因此,对于{foo: string, bar: object}
,它将变成{foo?: string, bar?: object} & {foo: string}
,这等效于{foo: string, bar?: object}
(并通过extends infer O
技巧转换为它)。
让我们来测试一下:
interface MyObject {
name: string;
age: number;
favorites: {
color: string
}
}
type MyNewObject = ObjectPropertiesOptional<MyObject>;
/*
type MyNewObject = {
name: string;
age: number;
favorites?: {
color: string;
} | undefined;
}
*/
看起来不错。`name`和`age`属性仍然是必需的,但`favorites`属性现在是可选的。
英文:
Here's one possible implementation:
type ObjectPropertiesOptional<T> = (
Partial<T> & { [K in keyof T as T[K] extends object ? never : K]: T[K] }
) extends infer O ? { [K in keyof O]: O[K] } : never;
The whole thing is wrapped in (
...) extends infer O ? { [K in keyof O]: O[K] } : never
which is a trick to make the compiler convert a relatively ugly interesection type like {foo: string} & {bar: number}
and turn it into a single object type like {foo: string; bar: number}
. This is the same technique as Expand<T>
as described in https://stackoverflow.com/q/57683303/2887218.
The actual implementation is to intersect Partial<T>
(using the Partial<T>
utility type to make every property optional) with a remapped version of T
that only includes non-object
properties. (By remapping a key to never
we suppress it).
So for {foo: string, bar: object}
, it would become {foo?: string, bar?: object} & {foo: string}
, which is equivalent to {foo: string, bar?: object}
(and converted to it by the extends infer O
trick).
Let's test it out:
interface MyObject {
name: string;
age: number;
favorites: {
color: string
}
}
type MyNewObject = ObjectPropertiesOptional<MyObject>;
/*
type MyNewObject = {
name: string;
age: number;
favorites?: {
color: string;
} | undefined;
}
*/
Looks good. The name
and age
properties are still required, but the favorites
property is now optional.
答案2
得分: 0
据我所知,在TypeScript中目前还不可能实现这个。
这是Github讨论的链接。
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论