typescript 使某个类型的所有对象属性可选

iyfamqjs  于 2023-03-13  发布在  TypeScript
关注(0)|答案(2)|浏览(253)

给定一个T类型,我如何使所有object属性都是可选的?
所以对于一个类型:

interface MyObject {
   name: string;
   age: number;
   favorites: {
     color: string
   }
}
type MyNewObject = ObjectPropertiesOptional<MyObject>;

它返回

interface MyNewObject {
   name: string;
   age: number;
   favorites?: {
     color: string
   }
}
6ie5vjzr

6ie5vjzr1#

下面是一个可能的实现:

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中,这是一个技巧,可以让编译器转换一个相对丑陋的interecection类型(如{foo: string} & {bar: number}),并将其转换为一个单一的对象类型(如{foo: string; bar: number}),这与How can I see the full expanded contract of a Typescript type?中描述的Expand<T>技术相同。
实际的实现是将Partial<T>(使用Partial<T>实用程序类型使每个属性都是可选的)与T的重Map版本相交,该重Map版本只包含非object属性(通过将键重Map到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;
}
*/

看起来不错。nameage属性仍然是必需的,但favorites属性现在是可选的。
Playground代码链接

8fq7wneg

8fq7wneg2#

据我所知,这在Typescript中还不可能。
这是Github discussion

相关问题