diff --git a/source/set-optional.d.ts b/source/set-optional.d.ts index 224004dcf..f2cfa9107 100644 --- a/source/set-optional.d.ts +++ b/source/set-optional.d.ts @@ -27,9 +27,11 @@ type SomeOptional = SetOptional; @category Object */ export type SetOptional = - Simplify< - // Pick just the keys that are readonly from the base type. - Except & - // Pick the keys that should be mutable from the base type and make them mutable. - Partial> - >; + BaseType extends unknown // To distribute `BaseType` when it's a union type. + ? Simplify< + // Pick just the keys that are readonly from the base type. + Except & + // Pick the keys that should be mutable from the base type and make them mutable. + Partial>> + > + : never; diff --git a/source/set-readonly.d.ts b/source/set-readonly.d.ts index f8f4aa90c..bb6b19084 100644 --- a/source/set-readonly.d.ts +++ b/source/set-readonly.d.ts @@ -33,6 +33,6 @@ export type SetReadonly = BaseType extends unknown ? Simplify< Except & - Readonly> + Readonly>> > : never; diff --git a/source/set-required.d.ts b/source/set-required.d.ts index 735c227c4..d7b00f4bb 100644 --- a/source/set-required.d.ts +++ b/source/set-required.d.ts @@ -35,6 +35,6 @@ export type SetRequired = // Pick just the keys that are optional from the base type. Except & // Pick the keys that should be required from the base type and make them required. - Required> + Required>> > : never; diff --git a/test-d/set-optional.ts b/test-d/set-optional.ts index 649b4ec07..aa7f8d1ac 100644 --- a/test-d/set-optional.ts +++ b/test-d/set-optional.ts @@ -16,3 +16,19 @@ expectType<{a?: number; b?: string; c?: boolean}>(variation3); // Fail if type changes even if optional is right. declare const variation4: SetOptional<{a: number; b?: string; c: boolean}, 'b' | 'c'>; expectNotAssignable<{a: boolean; b?: string; c?: boolean}>(variation4); + +// Preserves readonly modifier. +declare const variation5: SetOptional<{readonly a: number; readonly b?: string; c: boolean}, 'b' | 'c'>; +expectType<{readonly a: number; readonly b?: string; c?: boolean}>(variation5); + +// Works with unions. +declare const variation6: SetOptional<{readonly a: number; b: number; c: boolean} | {a: string; readonly b: string; d: boolean}, 'a' | 'b'>; +expectType<{readonly a?: number; b?: number; c: boolean} | {a?: string; readonly b?: string; d: boolean}>(variation6); + +// Marks all keys as optional, if `Keys` is `any`. +declare const variation7: SetOptional<{readonly a: number; b: string; c: boolean}, any>; +expectType<{readonly a?: number; b?: string; c?: boolean}>(variation7); + +// Does nothing, if `Keys` is `never`. +declare const variation8: SetOptional<{a?: number; readonly b?: string; readonly c: boolean}, never>; +expectType<{a?: number; readonly b?: string; readonly c: boolean}>(variation8); diff --git a/test-d/set-readonly.ts b/test-d/set-readonly.ts index d3d7dcf01..0ba0b9884 100644 --- a/test-d/set-readonly.ts +++ b/test-d/set-readonly.ts @@ -16,3 +16,19 @@ expectType<{readonly a: number; readonly b?: string; readonly c: boolean}>(varia // Fail if type changes even if readonly is right. declare const variation4: SetReadonly<{a: number; readonly b: string; c: boolean}, 'b' | 'c'>; expectNotAssignable<{a: boolean; readonly b: string; readonly c: boolean}>(variation4); + +// Preserves optional modifier. +declare const variation5: SetReadonly<{a?: number; readonly b?: string; c?: boolean}, 'b' | 'c'>; +expectType<{a?: number; readonly b?: string; readonly c?: boolean}>(variation5); + +// Works with unions. +declare const variation6: SetReadonly<{a?: number; b: number; c: boolean} | {a: string; b?: string; d: boolean}, 'a' | 'b'>; +expectType<{readonly a?: number; readonly b: number; c: boolean} | {readonly a: string; readonly b?: string; d: boolean}>(variation6); + +// Marks all keys as readonly, if `Keys` is `any`. +declare const variation7: SetReadonly<{a?: number; b: string; c: boolean}, any>; +expectType<{readonly a?: number; readonly b: string; readonly c: boolean}>(variation7); + +// Does nothing, if `Keys` is `never`. +declare const variation8: SetReadonly<{a: number; readonly b: string; readonly c: boolean}, never>; +expectType<{a: number; readonly b: string; readonly c: boolean}>(variation8); diff --git a/test-d/set-required.ts b/test-d/set-required.ts index 4094e9cc9..6e51f0333 100644 --- a/test-d/set-required.ts +++ b/test-d/set-required.ts @@ -20,3 +20,19 @@ expectNotAssignable<{a?: boolean; b: string; c: boolean}>(variation4); // Update one required and one optional to required in a union. declare const variation5: SetRequired<{a?: '1'; b: string; c?: boolean} | {a?: '2'; b: string; c?: boolean}, 'a' | 'b'>; expectType<{a: '1'; b: string; c?: boolean} | {a: '2'; b: string; c?: boolean}>(variation5); + +// Preserves readonly modifier. +declare const variation6: SetRequired<{readonly a?: number; readonly b: string; c?: boolean}, 'b' | 'c'>; +expectType<{readonly a?: number; readonly b: string; c: boolean}>(variation6); + +// Works with unions. +declare const variation7: SetRequired<{readonly a?: number; b?: number; c?: boolean} | {a?: string; readonly b?: string; d?: boolean}, 'a' | 'b'>; +expectType<{readonly a: number; b: number; c?: boolean} | {a: string; readonly b: string; d?: boolean}>(variation7); + +// Marks all keys as required, if `Keys` is `any`. +declare const variation8: SetRequired<{readonly a?: number; b?: string; c?: boolean}, any>; +expectType<{readonly a: number; b: string; c: boolean}>(variation8); + +// Does nothing, if `Keys` is `never`. +declare const variation9: SetRequired<{a?: number; readonly b?: string; readonly c: boolean}, never>; +expectType<{a?: number; readonly b?: string; readonly c: boolean}>(variation9);