Skip to content

Commit 5b76e3b

Browse files
authoredFeb 25, 2024
fix(core): improve NonReadonly type (#1237)
* fix(core): improve NonReadonly type fixes #1236 * docs(samples): update
1 parent 4fecbb2 commit 5b76e3b

File tree

9 files changed

+60
-59
lines changed

9 files changed

+60
-59
lines changed
 

‎packages/core/src/writers/types.ts

+26-25
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,28 @@
11
export const getOrvalGeneratedTypes = () => `
2-
// https://stackoverflow.com/questions/49579094/typescript-conditional-types-filter-out-readonly-properties-pick-only-requir/49579497#49579497
3-
type IfEquals<X, Y, A = X, B = never> = (<T>() => T extends X ? 1 : 2) extends <
4-
T,
5-
>() => T extends Y ? 1 : 2
6-
? A
7-
: B;
8-
9-
type WritableKeys<T> = {
10-
[P in keyof T]-?: IfEquals<
11-
{ [Q in P]: T[P] },
12-
{ -readonly [Q in P]: T[P] },
13-
P
14-
>;
15-
}[keyof T];
16-
17-
type UnionToIntersection<U> =
18-
(U extends any ? (k: U)=>void : never) extends ((k: infer I)=>void) ? I : never;
19-
type DistributeReadOnlyOverUnions<T> = T extends any ? NonReadonly<T> : never;
20-
21-
type Writable<T> = Pick<T, WritableKeys<T>>;
22-
type NonReadonly<T> = [T] extends [UnionToIntersection<T>] ? {
23-
[P in keyof Writable<T>]: T[P] extends object
24-
? NonReadonly<NonNullable<T[P]>>
25-
: T[P];
26-
} : DistributeReadOnlyOverUnions<T>;
2+
type IsAny<T> = 0 extends 1 & T ? true : false;
3+
type IsUnknown<T> = IsAny<T> extends true ? false : unknown extends T ? true : false;
4+
type Primitive = string | number | boolean | bigint | symbol | undefined | null;
5+
type isBuiltin = Primitive | Function | Date | Error | RegExp;
6+
type NonReadonly<T> =
7+
T extends Exclude<isBuiltin, Error>
8+
? T
9+
: T extends Map<infer Key, infer Value>
10+
? Map<NonReadonly<Key>, NonReadonly<Value>>
11+
: T extends ReadonlyMap<infer Key, infer Value>
12+
? Map<NonReadonly<Key>, NonReadonly<Value>>
13+
: T extends WeakMap<infer Key, infer Value>
14+
? WeakMap<NonReadonly<Key>, NonReadonly<Value>>
15+
: T extends Set<infer Values>
16+
? Set<NonReadonly<Values>>
17+
: T extends ReadonlySet<infer Values>
18+
? Set<NonReadonly<Values>>
19+
: T extends WeakSet<infer Values>
20+
? WeakSet<NonReadonly<Values>>
21+
: T extends Promise<infer Value>
22+
? Promise<NonReadonly<Value>>
23+
: T extends {}
24+
? { -readonly [Key in keyof T]: NonReadonly<T[Key]> }
25+
: IsUnknown<T> extends true
26+
? unknown
27+
: T;
2728
`;

‎samples/angular-app/src/api/endpoints/pets/pets.msw.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ export const getListPetsResponseMock = (overrideResponse: any = {}): Pets =>
1919
...overrideResponse,
2020
}));
2121

22-
export const getShowPetByIdResponseMock = (): Pet =>
22+
export const getShowPetByIdResponseMock = () =>
2323
(() => ({
2424
id: faker.number.int({ min: 1, max: 99 }),
2525
name: faker.person.firstName(),

‎samples/react-app-with-swr/src/api/endpoints/petstoreFromFileSpecWithTransformer.msw.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ export const getCreatePetsResponseMock = (overrideResponse: any = {}): Pet => ({
3030
...overrideResponse,
3131
});
3232

33-
export const getShowPetByIdResponseMock = (): Pet =>
33+
export const getShowPetByIdResponseMock = () =>
3434
(() => ({
3535
id: faker.number.int({ min: 1, max: 99 }),
3636
name: faker.person.firstName(),

‎samples/react-app/src/api/endpoints/petstoreFromFileSpecWithTransformer.msw.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ export const getListPetsResponseMock = (overrideResponse: any = {}): Pets =>
1919
...overrideResponse,
2020
}));
2121

22-
export const getShowPetByIdResponseMock = (): Pet =>
22+
export const getShowPetByIdResponseMock = () =>
2323
(() => ({
2424
id: faker.number.int({ min: 1, max: 99 }),
2525
name: faker.person.firstName(),

‎samples/react-query/basic/src/api/endpoints/petstoreFromFileSpecWithTransformer.msw.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -217,7 +217,7 @@ export const getUpdatePetsResponseMock = (overrideResponse: any = {}): Pet =>
217217
},
218218
]);
219219

220-
export const getShowPetByIdResponseMock = (): Pet =>
220+
export const getShowPetByIdResponseMock = () =>
221221
(() => ({
222222
id: faker.number.int({ min: 1, max: 99 }),
223223
name: faker.person.firstName(),

‎samples/react-query/basic/src/api/endpoints/petstoreFromFileSpecWithTransformer.ts

+27-27
Original file line numberDiff line numberDiff line change
@@ -36,33 +36,33 @@ import type {
3636
import { customInstance } from '../mutator/custom-instance';
3737
import type { ErrorType } from '../mutator/custom-instance';
3838

39-
// https://stackoverflow.com/questions/49579094/typescript-conditional-types-filter-out-readonly-properties-pick-only-requir/49579497#49579497
40-
type IfEquals<X, Y, A = X, B = never> =
41-
(<T>() => T extends X ? 1 : 2) extends <T>() => T extends Y ? 1 : 2 ? A : B;
42-
43-
type WritableKeys<T> = {
44-
[P in keyof T]-?: IfEquals<
45-
{ [Q in P]: T[P] },
46-
{ -readonly [Q in P]: T[P] },
47-
P
48-
>;
49-
}[keyof T];
50-
51-
type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends (
52-
k: infer I,
53-
) => void
54-
? I
55-
: never;
56-
type DistributeReadOnlyOverUnions<T> = T extends any ? NonReadonly<T> : never;
57-
58-
type Writable<T> = Pick<T, WritableKeys<T>>;
59-
type NonReadonly<T> = [T] extends [UnionToIntersection<T>]
60-
? {
61-
[P in keyof Writable<T>]: T[P] extends object
62-
? NonReadonly<NonNullable<T[P]>>
63-
: T[P];
64-
}
65-
: DistributeReadOnlyOverUnions<T>;
39+
type IsAny<T> = 0 extends 1 & T ? true : false;
40+
type IsUnknown<T> =
41+
IsAny<T> extends true ? false : unknown extends T ? true : false;
42+
type Primitive = string | number | boolean | bigint | symbol | undefined | null;
43+
type isBuiltin = Primitive | Function | Date | Error | RegExp;
44+
type NonReadonly<T> =
45+
T extends Exclude<isBuiltin, Error>
46+
? T
47+
: T extends Map<infer Key, infer Value>
48+
? Map<NonReadonly<Key>, NonReadonly<Value>>
49+
: T extends ReadonlyMap<infer Key, infer Value>
50+
? Map<NonReadonly<Key>, NonReadonly<Value>>
51+
: T extends WeakMap<infer Key, infer Value>
52+
? WeakMap<NonReadonly<Key>, NonReadonly<Value>>
53+
: T extends Set<infer Values>
54+
? Set<NonReadonly<Values>>
55+
: T extends ReadonlySet<infer Values>
56+
? Set<NonReadonly<Values>>
57+
: T extends WeakSet<infer Values>
58+
? WeakSet<NonReadonly<Values>>
59+
: T extends Promise<infer Value>
60+
? Promise<NonReadonly<Value>>
61+
: T extends {}
62+
? { -readonly [Key in keyof T]: NonReadonly<T[Key]> }
63+
: IsUnknown<T> extends true
64+
? unknown
65+
: T;
6666

6767
type AwaitedInput<T> = PromiseLike<T> | T;
6868

‎samples/react-query/custom-client/src/api/endpoints/petstoreFromFileSpecWithTransformer.msw.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ export const getCreatePetsResponseMock = (overrideResponse: any = {}): Pet => ({
5252
...overrideResponse,
5353
});
5454

55-
export const getShowPetByIdResponseMock = (): Pet =>
55+
export const getShowPetByIdResponseMock = () =>
5656
(() => ({
5757
id: faker.number.int({ min: 1, max: 99 }),
5858
name: faker.person.firstName(),

‎samples/svelte-query/src/api/endpoints/petstoreFromFileSpecWithTransformer.msw.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ export const getListPetsResponseMock = (overrideResponse: any = {}): Pets =>
1919
...overrideResponse,
2020
}));
2121

22-
export const getShowPetByIdResponseMock = (): Pet =>
22+
export const getShowPetByIdResponseMock = () =>
2323
(() => ({
2424
id: faker.number.int({ min: 1, max: 99 }),
2525
name: faker.person.firstName(),

‎samples/vue-query/src/api/endpoints/petstoreFromFileSpecWithTransformer.msw.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ export const getCreatePetsResponseMock = (overrideResponse: any = {}): Pet => ({
2828
...overrideResponse,
2929
});
3030

31-
export const getShowPetByIdResponseMock = (): Pet =>
31+
export const getShowPetByIdResponseMock = () =>
3232
(() => ({
3333
id: faker.number.int({ min: 1, max: 99 }),
3434
name: faker.person.firstName(),

0 commit comments

Comments
 (0)
Please sign in to comment.