Skip to content

Commit fdbcb11

Browse files
authored
SetOptional/SetRequired/SetReadonly: Fix when the second argument is any (#1007)
1 parent 9d79775 commit fdbcb11

File tree

6 files changed

+58
-8
lines changed

6 files changed

+58
-8
lines changed

source/set-optional.d.ts

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,11 @@ type SomeOptional = SetOptional<Foo, 'b' | 'c'>;
2727
@category Object
2828
*/
2929
export type SetOptional<BaseType, Keys extends keyof BaseType> =
30-
Simplify<
31-
// Pick just the keys that are readonly from the base type.
32-
Except<BaseType, Keys> &
33-
// Pick the keys that should be mutable from the base type and make them mutable.
34-
Partial<Pick<BaseType, Keys>>
35-
>;
30+
BaseType extends unknown // To distribute `BaseType` when it's a union type.
31+
? Simplify<
32+
// Pick just the keys that are readonly from the base type.
33+
Except<BaseType, Keys> &
34+
// Pick the keys that should be mutable from the base type and make them mutable.
35+
Partial<Except<BaseType, Exclude<keyof BaseType, Keys>>>
36+
>
37+
: never;

source/set-readonly.d.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,6 @@ export type SetReadonly<BaseType, Keys extends keyof BaseType> =
3333
BaseType extends unknown
3434
? Simplify<
3535
Except<BaseType, Keys> &
36-
Readonly<Pick<BaseType, Keys>>
36+
Readonly<Except<BaseType, Exclude<keyof BaseType, Keys>>>
3737
>
3838
: never;

source/set-required.d.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,6 @@ export type SetRequired<BaseType, Keys extends keyof BaseType> =
3535
// Pick just the keys that are optional from the base type.
3636
Except<BaseType, Keys> &
3737
// Pick the keys that should be required from the base type and make them required.
38-
Required<Pick<BaseType, Keys>>
38+
Required<Except<BaseType, Exclude<keyof BaseType, Keys>>>
3939
>
4040
: never;

test-d/set-optional.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,19 @@ expectType<{a?: number; b?: string; c?: boolean}>(variation3);
1616
// Fail if type changes even if optional is right.
1717
declare const variation4: SetOptional<{a: number; b?: string; c: boolean}, 'b' | 'c'>;
1818
expectNotAssignable<{a: boolean; b?: string; c?: boolean}>(variation4);
19+
20+
// Preserves readonly modifier.
21+
declare const variation5: SetOptional<{readonly a: number; readonly b?: string; c: boolean}, 'b' | 'c'>;
22+
expectType<{readonly a: number; readonly b?: string; c?: boolean}>(variation5);
23+
24+
// Works with unions.
25+
declare const variation6: SetOptional<{readonly a: number; b: number; c: boolean} | {a: string; readonly b: string; d: boolean}, 'a' | 'b'>;
26+
expectType<{readonly a?: number; b?: number; c: boolean} | {a?: string; readonly b?: string; d: boolean}>(variation6);
27+
28+
// Marks all keys as optional, if `Keys` is `any`.
29+
declare const variation7: SetOptional<{readonly a: number; b: string; c: boolean}, any>;
30+
expectType<{readonly a?: number; b?: string; c?: boolean}>(variation7);
31+
32+
// Does nothing, if `Keys` is `never`.
33+
declare const variation8: SetOptional<{a?: number; readonly b?: string; readonly c: boolean}, never>;
34+
expectType<{a?: number; readonly b?: string; readonly c: boolean}>(variation8);

test-d/set-readonly.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,19 @@ expectType<{readonly a: number; readonly b?: string; readonly c: boolean}>(varia
1616
// Fail if type changes even if readonly is right.
1717
declare const variation4: SetReadonly<{a: number; readonly b: string; c: boolean}, 'b' | 'c'>;
1818
expectNotAssignable<{a: boolean; readonly b: string; readonly c: boolean}>(variation4);
19+
20+
// Preserves optional modifier.
21+
declare const variation5: SetReadonly<{a?: number; readonly b?: string; c?: boolean}, 'b' | 'c'>;
22+
expectType<{a?: number; readonly b?: string; readonly c?: boolean}>(variation5);
23+
24+
// Works with unions.
25+
declare const variation6: SetReadonly<{a?: number; b: number; c: boolean} | {a: string; b?: string; d: boolean}, 'a' | 'b'>;
26+
expectType<{readonly a?: number; readonly b: number; c: boolean} | {readonly a: string; readonly b?: string; d: boolean}>(variation6);
27+
28+
// Marks all keys as readonly, if `Keys` is `any`.
29+
declare const variation7: SetReadonly<{a?: number; b: string; c: boolean}, any>;
30+
expectType<{readonly a?: number; readonly b: string; readonly c: boolean}>(variation7);
31+
32+
// Does nothing, if `Keys` is `never`.
33+
declare const variation8: SetReadonly<{a: number; readonly b: string; readonly c: boolean}, never>;
34+
expectType<{a: number; readonly b: string; readonly c: boolean}>(variation8);

test-d/set-required.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,3 +20,19 @@ expectNotAssignable<{a?: boolean; b: string; c: boolean}>(variation4);
2020
// Update one required and one optional to required in a union.
2121
declare const variation5: SetRequired<{a?: '1'; b: string; c?: boolean} | {a?: '2'; b: string; c?: boolean}, 'a' | 'b'>;
2222
expectType<{a: '1'; b: string; c?: boolean} | {a: '2'; b: string; c?: boolean}>(variation5);
23+
24+
// Preserves readonly modifier.
25+
declare const variation6: SetRequired<{readonly a?: number; readonly b: string; c?: boolean}, 'b' | 'c'>;
26+
expectType<{readonly a?: number; readonly b: string; c: boolean}>(variation6);
27+
28+
// Works with unions.
29+
declare const variation7: SetRequired<{readonly a?: number; b?: number; c?: boolean} | {a?: string; readonly b?: string; d?: boolean}, 'a' | 'b'>;
30+
expectType<{readonly a: number; b: number; c?: boolean} | {a: string; readonly b: string; d?: boolean}>(variation7);
31+
32+
// Marks all keys as required, if `Keys` is `any`.
33+
declare const variation8: SetRequired<{readonly a?: number; b?: string; c?: boolean}, any>;
34+
expectType<{readonly a: number; b: string; c: boolean}>(variation8);
35+
36+
// Does nothing, if `Keys` is `never`.
37+
declare const variation9: SetRequired<{a?: number; readonly b?: string; readonly c: boolean}, never>;
38+
expectType<{a?: number; readonly b?: string; readonly c: boolean}>(variation9);

0 commit comments

Comments
 (0)