@planet-matrix/mobius-model 0.3.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +15 -0
- package/README.md +30 -1
- package/dist/index.js +4 -2
- package/dist/index.js.map +22 -4
- package/package.json +3 -3
- package/scripts/build.ts +4 -4
- package/src/basic/README.md +144 -0
- package/src/basic/array.ts +872 -0
- package/src/basic/bigint.ts +114 -0
- package/src/basic/boolean.ts +180 -0
- package/src/basic/enhance.ts +10 -0
- package/src/basic/error.ts +51 -0
- package/src/basic/function.ts +453 -0
- package/src/basic/helper.ts +276 -0
- package/src/basic/index.ts +17 -0
- package/src/basic/is.ts +320 -0
- package/src/basic/number.ts +178 -0
- package/src/basic/object.ts +140 -0
- package/src/basic/promise.ts +464 -0
- package/src/basic/regexp.ts +7 -0
- package/src/basic/stream.ts +140 -0
- package/src/basic/string.ts +308 -0
- package/src/basic/symbol.ts +164 -0
- package/src/basic/temporal.ts +224 -0
- package/src/encoding/README.md +105 -0
- package/src/encoding/base64.ts +98 -0
- package/src/encoding/index.ts +1 -0
- package/src/index.ts +4 -0
- package/src/random/README.md +109 -0
- package/src/random/index.ts +1 -0
- package/src/random/uuid.ts +103 -0
- package/src/type/README.md +330 -0
- package/src/type/array.ts +5 -0
- package/src/type/boolean.ts +471 -0
- package/src/type/class.ts +419 -0
- package/src/type/function.ts +1519 -0
- package/src/type/helper.ts +135 -0
- package/src/type/index.ts +14 -0
- package/src/type/intersection.ts +93 -0
- package/src/type/is.ts +247 -0
- package/src/type/iteration.ts +233 -0
- package/src/type/number.ts +732 -0
- package/src/type/object.ts +788 -0
- package/src/type/path.ts +73 -0
- package/src/type/string.ts +1004 -0
- package/src/type/tuple.ts +2424 -0
- package/src/type/union.ts +108 -0
- package/tests/unit/basic/array.spec.ts +290 -0
- package/tests/unit/basic/bigint.spec.ts +50 -0
- package/tests/unit/basic/boolean.spec.ts +74 -0
- package/tests/unit/basic/error.spec.ts +32 -0
- package/tests/unit/basic/function.spec.ts +175 -0
- package/tests/unit/basic/helper.spec.ts +118 -0
- package/tests/unit/basic/number.spec.ts +74 -0
- package/tests/unit/basic/object.spec.ts +46 -0
- package/tests/unit/basic/promise.spec.ts +232 -0
- package/tests/unit/basic/regexp.spec.ts +11 -0
- package/tests/unit/basic/stream.spec.ts +120 -0
- package/tests/unit/basic/string.spec.ts +74 -0
- package/tests/unit/basic/symbol.spec.ts +72 -0
- package/tests/unit/basic/temporal.spec.ts +78 -0
- package/tests/unit/encoding/base64.spec.ts +40 -0
- package/tests/unit/random/uuid.spec.ts +37 -0
- package/dist/index.d.ts +0 -2
- package/dist/index.d.ts.map +0 -1
- package/dist/reactor/index.d.ts +0 -3
- package/dist/reactor/index.d.ts.map +0 -1
- package/dist/reactor/reactor-core/flags.d.ts +0 -99
- package/dist/reactor/reactor-core/flags.d.ts.map +0 -1
- package/dist/reactor/reactor-core/index.d.ts +0 -4
- package/dist/reactor/reactor-core/index.d.ts.map +0 -1
- package/dist/reactor/reactor-core/primitive.d.ts +0 -276
- package/dist/reactor/reactor-core/primitive.d.ts.map +0 -1
- package/dist/reactor/reactor-core/reactive-system.d.ts +0 -241
- package/dist/reactor/reactor-core/reactive-system.d.ts.map +0 -1
- package/dist/reactor/reactor-operators/branch.d.ts +0 -19
- package/dist/reactor/reactor-operators/branch.d.ts.map +0 -1
- package/dist/reactor/reactor-operators/convert.d.ts +0 -30
- package/dist/reactor/reactor-operators/convert.d.ts.map +0 -1
- package/dist/reactor/reactor-operators/create.d.ts +0 -26
- package/dist/reactor/reactor-operators/create.d.ts.map +0 -1
- package/dist/reactor/reactor-operators/filter.d.ts +0 -269
- package/dist/reactor/reactor-operators/filter.d.ts.map +0 -1
- package/dist/reactor/reactor-operators/index.d.ts +0 -8
- package/dist/reactor/reactor-operators/index.d.ts.map +0 -1
- package/dist/reactor/reactor-operators/join.d.ts +0 -48
- package/dist/reactor/reactor-operators/join.d.ts.map +0 -1
- package/dist/reactor/reactor-operators/map.d.ts +0 -165
- package/dist/reactor/reactor-operators/map.d.ts.map +0 -1
- package/dist/reactor/reactor-operators/utility.d.ts +0 -48
- package/dist/reactor/reactor-operators/utility.d.ts.map +0 -1
|
@@ -0,0 +1,788 @@
|
|
|
1
|
+
// oxlint-disable no-empty-object-type
|
|
2
|
+
// oxlint-disable no-unsafe-function-type
|
|
3
|
+
// oxlint-disable ban-types
|
|
4
|
+
// oxlint-disable no-explicit-any
|
|
5
|
+
|
|
6
|
+
import type {
|
|
7
|
+
Nilable,
|
|
8
|
+
NonNilable,
|
|
9
|
+
NonNullable,
|
|
10
|
+
NonUndefinedable,
|
|
11
|
+
Nullable,
|
|
12
|
+
Undefinedable,
|
|
13
|
+
} from "./is.ts"
|
|
14
|
+
import type { UnionComplement, UnionDifference, UnionIntersection } from "./union.ts"
|
|
15
|
+
|
|
16
|
+
// ============================================================================
|
|
17
|
+
// Primitives
|
|
18
|
+
// ============================================================================
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Strict version of `Omit`, `K` must be subset of `typeof T`.
|
|
22
|
+
*/
|
|
23
|
+
export type StrictOmit<T, K extends keyof T> = Omit<T, K>
|
|
24
|
+
|
|
25
|
+
export type StringRecord<T> = Record<string, T>
|
|
26
|
+
export type NumberRecord<T> = Record<number, T>
|
|
27
|
+
export type SymbolRecord<T> = Record<symbol, T>
|
|
28
|
+
export type HybridRecord<T> = Record<string | number | symbol, T>
|
|
29
|
+
export type AnyStringRecord = StringRecord<any>
|
|
30
|
+
export type AnyNumberRecord = NumberRecord<any>
|
|
31
|
+
export type AnySymbolRecord = SymbolRecord<any>
|
|
32
|
+
export type AnyHybridRecord = Record<string | number | symbol, any>
|
|
33
|
+
export type AnyRecord = AnyStringRecord | AnyNumberRecord | AnySymbolRecord
|
|
34
|
+
|
|
35
|
+
export type ObjectExact<A extends object> = A & { __brand: keyof A };
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* @see {@link https://stackoverflow.com/questions/78453542/intersection-with-object-in-prettify-helper-type}
|
|
39
|
+
* @see {@link https://github.com/mylesmmurphy/prettify-ts}
|
|
40
|
+
*/
|
|
41
|
+
export type ObjectPrettify<Target extends AnyHybridRecord> = Pick<Target, keyof Target>
|
|
42
|
+
export type ObjectPrettify2<Target extends AnyHybridRecord> = Target extends infer O ? { [K in keyof O]: O[K] } : never
|
|
43
|
+
|
|
44
|
+
// ============================================================================
|
|
45
|
+
// Validation
|
|
46
|
+
// ============================================================================
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* If the `Target` is an empty Record/Object, then return `true`.
|
|
50
|
+
*
|
|
51
|
+
* @example
|
|
52
|
+
* ```
|
|
53
|
+
* // Expect: true
|
|
54
|
+
* type Example1 = ObjectIsEmpty<{}>
|
|
55
|
+
* // Expect: false
|
|
56
|
+
* type Example2 = ObjectIsEmpty<{ a: number }>
|
|
57
|
+
* ```
|
|
58
|
+
*/
|
|
59
|
+
export type ObjectIsEmpty<Target extends AnyStringRecord> = keyof Target extends never ? true : false
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* If the `Target` is an empty Record/Object, then return `never`.
|
|
63
|
+
*
|
|
64
|
+
* @see {@link https://github.com/ts-essentials/ts-essentials#nonemptyobject}
|
|
65
|
+
* @see {@link https://github.com/ts-essentials/ts-essentials/tree/master/lib/non-empty-object}
|
|
66
|
+
*/
|
|
67
|
+
export type ObjectNonEmpty<Target extends AnyStringRecord> = keyof Target extends never ? never : Target
|
|
68
|
+
|
|
69
|
+
// ============================================================================
|
|
70
|
+
// Extraction
|
|
71
|
+
// ============================================================================
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* @example
|
|
75
|
+
* ```
|
|
76
|
+
* interface Props { name: string, age: number, visible: boolean }
|
|
77
|
+
* // Expect: 'name' | 'age' | 'visible'
|
|
78
|
+
* type Example1 = ObjectKeys<Props>
|
|
79
|
+
* ```
|
|
80
|
+
*/
|
|
81
|
+
export type ObjectKeys<Target> = Target extends AnyHybridRecord ? keyof Target : never
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* @example
|
|
85
|
+
* ```
|
|
86
|
+
* interface Props { name: string, age: number, visible: boolean }
|
|
87
|
+
* // Expect: string | number | boolean
|
|
88
|
+
* type Example1 = ObjectValues<Props>
|
|
89
|
+
* ```
|
|
90
|
+
*/
|
|
91
|
+
export type ObjectValues<Target> = Target extends AnyHybridRecord ? Target[keyof Target] : never
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* @example
|
|
95
|
+
* ```
|
|
96
|
+
* type MixedProps = {name: string; setName: (name: string) => void; someKeys?: string; someFn?: (...args: any) => any;};
|
|
97
|
+
*
|
|
98
|
+
* // Expect: "setName | someFn"
|
|
99
|
+
* type Example1 = FunctionKeys<MixedProps>
|
|
100
|
+
* ```
|
|
101
|
+
* @see {@link https://github.com/piotrwitek/utility-types/blob/master/src/mapped-types.ts}
|
|
102
|
+
*/
|
|
103
|
+
export type FunctionKeys<Target extends AnyHybridRecord> = {
|
|
104
|
+
[Key in keyof Target]-?: NonUndefinedable<Target[Key]> extends Function ? Key : never;
|
|
105
|
+
}[keyof Target]
|
|
106
|
+
/**
|
|
107
|
+
* @example
|
|
108
|
+
* ```
|
|
109
|
+
* type MixedProps = {name: string; setName: (name: string) => void; someKeys?: string; someFn?: (...args: any) => any;};
|
|
110
|
+
*
|
|
111
|
+
* // Expect: "name | someKey"
|
|
112
|
+
* type Example1 = NonFunctionKeys<MixedProps>
|
|
113
|
+
* ```
|
|
114
|
+
* @see {@link https://github.com/piotrwitek/utility-types/blob/master/src/mapped-types.ts}
|
|
115
|
+
*/
|
|
116
|
+
export type NonFunctionKeys<Target extends AnyHybridRecord> = {
|
|
117
|
+
[Key in keyof Target]-?: NonUndefinedable<Target[Key]> extends Function ? never : Key;
|
|
118
|
+
}[keyof Target]
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* @see {@link https://github.com/ts-essentials/ts-essentials/blob/5aa1f264e77fb36bb3f673c49f00927c7c181a7f/lib/types.ts#L440 warning}
|
|
122
|
+
* @see {@link https://stackoverflow.com/a/52473108/1815209 explain with comments}
|
|
123
|
+
*/
|
|
124
|
+
type IfEquals<X, Y, A = X, B = never> = (<T>() => T extends X ? 1 : 2) extends (<T>() => T extends Y ? 1 : 2) ? A : B
|
|
125
|
+
/**
|
|
126
|
+
* @example
|
|
127
|
+
* ```
|
|
128
|
+
* type Props = { readonly foo: string; bar: number };
|
|
129
|
+
* // Expect: "foo"
|
|
130
|
+
* type Example1 = ReadonlyKeys<Props>
|
|
131
|
+
* ```
|
|
132
|
+
* @see {@link https://github.com/piotrwitek/utility-types/blob/master/src/mapped-types.ts}
|
|
133
|
+
* @see {@link https://stackoverflow.com/questions/52443276/how-to-exclude-getter-only-properties-from-type-in-typescript}
|
|
134
|
+
*/
|
|
135
|
+
export type ReadonlyKeys<Target extends AnyHybridRecord> = {
|
|
136
|
+
[Key in keyof Target]-?: IfEquals<{ [Q in Key]: Target[Key] }, { -readonly [Q in Key]: Target[Key] }, never, Key>
|
|
137
|
+
}[keyof Target]
|
|
138
|
+
/**
|
|
139
|
+
* @example
|
|
140
|
+
* ```
|
|
141
|
+
* interface Props { readonly foo: string, bar: number }
|
|
142
|
+
* // Expect: "bar"
|
|
143
|
+
* type Example1 = WritableKeys<Props>
|
|
144
|
+
* ```
|
|
145
|
+
* @see {@link https://github.com/piotrwitek/utility-types/blob/master/src/mapped-types.ts}
|
|
146
|
+
* @see {@link https://stackoverflow.com/questions/52443276/how-to-exclude-getter-only-properties-from-type-in-typescript}
|
|
147
|
+
*/
|
|
148
|
+
export type WritableKeys<Target extends AnyHybridRecord> = {
|
|
149
|
+
[Key in keyof Target]-?: IfEquals<{ [Q in Key]: Target[Key] }, { -readonly [Q in Key]: Target[Key] }, Key, never>
|
|
150
|
+
}[keyof Target]
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* @example
|
|
154
|
+
* ```
|
|
155
|
+
* type Props = { req: number; reqUndef: number | undefined; opt?: string; optUndef?: number | undefined; };
|
|
156
|
+
* // Expect: "req" | "reqUndef"
|
|
157
|
+
* type Example1 = RequiredKeys<Props>
|
|
158
|
+
* ```
|
|
159
|
+
* @see {@link https://github.com/piotrwitek/utility-types/blob/master/src/mapped-types.ts}
|
|
160
|
+
* @see {@link https://stackoverflow.com/questions/52984808/is-there-a-way-to-get-all-required-properties-of-a-typescript-object}
|
|
161
|
+
*/
|
|
162
|
+
export type RequiredKeys<Target> = {
|
|
163
|
+
[Key in keyof Target]-?: Record<string | number | symbol, never> extends Pick<Target, Key> ? never : Key;
|
|
164
|
+
}[keyof Target]
|
|
165
|
+
/**
|
|
166
|
+
* @example
|
|
167
|
+
* ```
|
|
168
|
+
* type Props = { req: number; reqUndef: number | undefined; opt?: string; optUndef?: number | undefined; };
|
|
169
|
+
* // Expect: "opt" | "optUndef"
|
|
170
|
+
* type Example1 = OptionalKeys<Props>
|
|
171
|
+
* ```
|
|
172
|
+
* @see {@link https://github.com/piotrwitek/utility-types/blob/master/src/mapped-types.ts}
|
|
173
|
+
* @see {@link https://stackoverflow.com/questions/52984808/is-there-a-way-to-get-all-required-properties-of-a-typescript-object}
|
|
174
|
+
*/
|
|
175
|
+
export type OptionalKeys<Target> = {
|
|
176
|
+
[Key in keyof Target]-?: Record<string | number | symbol, never> extends Pick<Target, Key> ? Key : never;
|
|
177
|
+
}[keyof Target]
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* @example
|
|
181
|
+
* ```
|
|
182
|
+
* interface Temp { req: number, reqUndef: number | undefined, opt?: string }
|
|
183
|
+
* // Expect: 'req'
|
|
184
|
+
* type Example1 = PickKeysByValue<Temp, number>
|
|
185
|
+
* // Expect: 'req' | 'reqUndef'
|
|
186
|
+
* type Example2 = PickKeysByValue<Temp, number | undefined>
|
|
187
|
+
* ```
|
|
188
|
+
* (For ALL `ByValue` utilities) When we want to get 'opt' as result in above example, `PickKeysByValue<Temp, string>`
|
|
189
|
+
* will not work. We should use `PickKeysByValue<Temp, string | undefined>` instead. It's so weird that we don't always
|
|
190
|
+
* know whether the target key is optional or not in actual most of situations so we have to include `undefined`
|
|
191
|
+
* in the target matching `ValueType`'s union. It's unnecessary and redundant.
|
|
192
|
+
*
|
|
193
|
+
* On the other hand, normal keys and optional keys are quite different. We indeed need an approach to
|
|
194
|
+
* distinguish them. Seems like add `undefined` to the union of optional keys' value type is a reasonable way.
|
|
195
|
+
*
|
|
196
|
+
* Here our final choice is give `undefined` a chance until we get a more fantastic solution. Meanwhile, turn the
|
|
197
|
+
* `exactOptionalPropertyTypes: true` typescript's compiler option on. It will make the use of `undefined` on optional
|
|
198
|
+
* properties more reasonable. For more information on it: see {@link https://www.typescriptlang.org/tsconfig#exactOptionalPropertyTypes},
|
|
199
|
+
* there's also a use guide on that information, see {@link https://tkdodo.eu/blog/optional-vs-undefined}.
|
|
200
|
+
*/
|
|
201
|
+
export type PickKeysByValue<Target, ValueType> = {
|
|
202
|
+
[Key in keyof Target]-?: Target[Key] extends ValueType ? Key : never
|
|
203
|
+
}[keyof Target]
|
|
204
|
+
/**
|
|
205
|
+
* @example
|
|
206
|
+
* ```
|
|
207
|
+
* interface Temp { req: number, reqUndef: number | undefined, opt?: string }
|
|
208
|
+
* // Expect: 'req'
|
|
209
|
+
* type Example1 = PickKeysByValue<Temp, number>
|
|
210
|
+
* // Expect: 'reqUndef'
|
|
211
|
+
* type Example2 = PickKeysByValue<Temp, number | undefined>
|
|
212
|
+
* ```
|
|
213
|
+
*/
|
|
214
|
+
export type PickKeysByValueExact<Target, ValueType> = {
|
|
215
|
+
[Key in keyof Target]-?: [ValueType] extends [Target[Key]] ? ([Target[Key]] extends [ValueType] ? Key : never) : never;
|
|
216
|
+
}[keyof Target]
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* @example
|
|
220
|
+
* ```
|
|
221
|
+
* interface Temp { req: number, reqUndef: number | undefined, opt?: string }
|
|
222
|
+
* // Expect: { req: number }
|
|
223
|
+
* type Example1 = PickByValue<Temp, number>
|
|
224
|
+
* // Expect: { req: number; reqUndef: number | undefined; }
|
|
225
|
+
* type Example2 = PickByValue<Temp, number | undefined>
|
|
226
|
+
* ```
|
|
227
|
+
* @see {@link https://medium.com/dailyjs/typescript-create-a-condition-based-subset-types-9d902cea5b8c}
|
|
228
|
+
*/
|
|
229
|
+
export type PickByValue<Target, ValueType> = Pick<Target, PickKeysByValue<Target, ValueType>>
|
|
230
|
+
/**
|
|
231
|
+
* @example
|
|
232
|
+
* ```
|
|
233
|
+
* interface Temp { req: number, reqUndef: number | undefined, opt?: string }
|
|
234
|
+
* // Expect: { req: number }
|
|
235
|
+
* type Example1 = PickByValueExact<Temp, number>
|
|
236
|
+
* // Expect: { reqUndef: number | undefined; }
|
|
237
|
+
* type Example2 = PickByValueExact<Temp, number | undefined>
|
|
238
|
+
* ```
|
|
239
|
+
* @see {@link https://github.com/piotrwitek/utility-types/blob/master/src/mapped-types.ts}
|
|
240
|
+
*/
|
|
241
|
+
export type PickByValueExact<Target, ValueType> = Pick<Target, PickKeysByValueExact<Target, ValueType>>
|
|
242
|
+
|
|
243
|
+
/**
|
|
244
|
+
* @example
|
|
245
|
+
* ```
|
|
246
|
+
* interface Temp { req: number, reqUndef: number | undefined, opt?: string }
|
|
247
|
+
* // Expect: { reqUndef: number | undefined; opt?: string; }
|
|
248
|
+
* type Example1 = OmitByValue<Temp, number>
|
|
249
|
+
* // Expect: { opt?: string; }
|
|
250
|
+
* type Example2 = OmitByValue<Temp, number | undefined>
|
|
251
|
+
* ```
|
|
252
|
+
* @see {@link https://medium.com/dailyjs/typescript-create-a-condition-based-subset-types-9d902cea5b8c}
|
|
253
|
+
*/
|
|
254
|
+
export type OmitByValue<Target, ValueType> = Omit<Target, PickKeysByValue<Target, ValueType>>
|
|
255
|
+
/**
|
|
256
|
+
* @example
|
|
257
|
+
* ```
|
|
258
|
+
* interface Temp { req: number, reqUndef: number | undefined, opt?: string }
|
|
259
|
+
* // Expect: { reqUndef: number | undefined; opt?: string; }
|
|
260
|
+
* type Example1 = OmitByValueExact<Temp, number>
|
|
261
|
+
* // Expect: { req: number; opt?: string }
|
|
262
|
+
* type Example2 = OmitByValueExact<Temp, number | undefined>
|
|
263
|
+
* ```
|
|
264
|
+
* @see {@link https://github.com/piotrwitek/utility-types/blob/master/src/mapped-types.ts}
|
|
265
|
+
*/
|
|
266
|
+
export type OmitByValueExact<Target, ValueType> = Omit<Target, PickKeysByValueExact<Target, ValueType>>
|
|
267
|
+
|
|
268
|
+
/**
|
|
269
|
+
* ObjectNamedKeys
|
|
270
|
+
* @example
|
|
271
|
+
* ```
|
|
272
|
+
* interface Temp {
|
|
273
|
+
* name: string
|
|
274
|
+
* age?: number
|
|
275
|
+
* [key: string]: string | number
|
|
276
|
+
* }
|
|
277
|
+
* // Expect: 'name' | 'age'
|
|
278
|
+
* type Example1 = ObjectNamedKeys<Temp>
|
|
279
|
+
* ```
|
|
280
|
+
* @see {@link https://github.com/millsp/ts-toolbelt/blob/319e55123b9571d49f34eca3e5926e41ca73e0f3/sources/Any/KnownKeys.ts#L11}
|
|
281
|
+
* @see {@link https://github.com/millsp/ts-toolbelt/issues/164 issue}
|
|
282
|
+
* @see {@link https://stackoverflow.com/questions/51465182/how-to-remove-index-signature-using-mapped-types/51956054#51956054}
|
|
283
|
+
*/
|
|
284
|
+
export type ObjectNamedKeys<Target> = keyof {
|
|
285
|
+
[Key in keyof Target as (
|
|
286
|
+
string extends Key ? never : number extends Key ? never : symbol extends Key ? never : Key
|
|
287
|
+
)]: Target[Key]
|
|
288
|
+
}
|
|
289
|
+
export type ObjectNamedParts<Target> = ObjectPrettify<Pick<Target, ObjectNamedKeys<Target>>>
|
|
290
|
+
export type ObjectIndexedParts<Target> = ObjectPrettify<Omit<Target, ObjectNamedKeys<Target>>>
|
|
291
|
+
export type ObjectHasNamedKeys<Target> = ObjectNamedKeys<Target> extends never ? false : true
|
|
292
|
+
export type ObjectHasIndexedKeys<Target> = keyof ObjectIndexedParts<Target> extends never ? false : true
|
|
293
|
+
|
|
294
|
+
// ============================================================================
|
|
295
|
+
// Manipulation
|
|
296
|
+
// ============================================================================
|
|
297
|
+
|
|
298
|
+
/**
|
|
299
|
+
* @example
|
|
300
|
+
* ```
|
|
301
|
+
* interface Temp { a: string, b: number, c?: boolean }
|
|
302
|
+
* // Expect: { a: string | undefined, b: number, c?: boolean }
|
|
303
|
+
* type Example1 = UndefinedableByKeys<Temp, 'a'>
|
|
304
|
+
* ```
|
|
305
|
+
*/
|
|
306
|
+
export type UndefinedableByKeys<Target, Keys> = {
|
|
307
|
+
[Key in keyof Target]: Key extends Keys ? Undefinedable<Target[Key]> : Target[Key]
|
|
308
|
+
}
|
|
309
|
+
export type UndefinedableAllKeys<Target> = UndefinedableByKeys<Target, keyof Target>
|
|
310
|
+
|
|
311
|
+
/**
|
|
312
|
+
* @example
|
|
313
|
+
* ```
|
|
314
|
+
* interface Temp { a: string, b: number, c?: boolean }
|
|
315
|
+
* // Expect: { a: string | null, b: number, c?: boolean }
|
|
316
|
+
* type Example1 = NullableByKeys<Temp, 'a'>
|
|
317
|
+
* ```
|
|
318
|
+
*/
|
|
319
|
+
export type NullableByKeys<Target, Keys> = {
|
|
320
|
+
[Key in keyof Target]: Key extends Keys ? Nullable<Target[Key]> : Target[Key]
|
|
321
|
+
}
|
|
322
|
+
export type NullableAllKeys<Target> = NullableByKeys<Target, keyof Target>
|
|
323
|
+
|
|
324
|
+
/**
|
|
325
|
+
* @example
|
|
326
|
+
* ```
|
|
327
|
+
* interface Temp { a: string, b: number, c?: boolean }
|
|
328
|
+
* // Expect: { a: string | null | undefined, b: number, c?: boolean }
|
|
329
|
+
* type Example1 = NilableByKeys<Temp, 'a'>
|
|
330
|
+
* ```
|
|
331
|
+
*/
|
|
332
|
+
export type NilableByKeys<Target, Keys> = {
|
|
333
|
+
[Key in keyof Target]: Key extends Keys ? Nilable<Target[Key]> : Target[Key]
|
|
334
|
+
}
|
|
335
|
+
export type NilableAllKeys<Target> = NilableByKeys<Target, keyof Target>
|
|
336
|
+
|
|
337
|
+
/**
|
|
338
|
+
* @example
|
|
339
|
+
* ```
|
|
340
|
+
* interface Temp { a: string | undefined, b: number, c?: boolean | undefined }
|
|
341
|
+
* // Expect: { a: string, b: number, c?: boolean }
|
|
342
|
+
* type Example1 = NonUndefinedableAllKeys<Temp>
|
|
343
|
+
* ```
|
|
344
|
+
*/
|
|
345
|
+
export type NonUndefinedableAllKeys<Target> = {
|
|
346
|
+
[Key in keyof Target]: NonUndefinedable<Target[Key]>
|
|
347
|
+
}
|
|
348
|
+
/**
|
|
349
|
+
* @example
|
|
350
|
+
* ```
|
|
351
|
+
* interface Temp { a: string | undefined, b: number, c?: boolean }
|
|
352
|
+
* // Expect: { a: string, b: number, c?: boolean }
|
|
353
|
+
* type Example1 = NonUndefinedableByKeys<Temp, 'a'>
|
|
354
|
+
* type Example2 = NonUndefinedableByKeys<Temp, 'a' | 'b'>
|
|
355
|
+
*
|
|
356
|
+
* interface Temp { a: string | undefined, b: number, c?: boolean | undefined }
|
|
357
|
+
* // Expect: { a: string, b: number, c?: boolean }
|
|
358
|
+
* type Example3 = NonUndefinedableByKeys<Temp, 'a' | 'c'>
|
|
359
|
+
* // Expect: { a: string | undefined, b: number, c?: boolean }
|
|
360
|
+
* type Example4 = NonUndefinedableByKeys<Temp, 'c'>
|
|
361
|
+
* ```
|
|
362
|
+
*/
|
|
363
|
+
export type NonUndefinedableByKeys<Target, Keys> = ObjectPrettify<
|
|
364
|
+
NonUndefinedableAllKeys<Pick<Target, UnionIntersection<RequiredKeys<Target>, Keys>>>
|
|
365
|
+
& Pick<Target, UnionDifference<RequiredKeys<Target>, Keys>>
|
|
366
|
+
& Partial<NonUndefinedableAllKeys<Pick<Target, UnionIntersection<OptionalKeys<Target>, Keys>>>>
|
|
367
|
+
& Pick<Target, UnionDifference<OptionalKeys<Target>, Keys>>
|
|
368
|
+
>
|
|
369
|
+
|
|
370
|
+
/**
|
|
371
|
+
* @example
|
|
372
|
+
* ```
|
|
373
|
+
* interface Temp { a: string | null, b: number, c?: boolean | null }
|
|
374
|
+
* // Expect: { a: string, b: number, c?: boolean }
|
|
375
|
+
* type Example1 = NonNullableAllKeys<Temp>
|
|
376
|
+
* ```
|
|
377
|
+
*/
|
|
378
|
+
export type NonNullableAllKeys<Target> = {
|
|
379
|
+
[Key in keyof Target]: NonNullable<Target[Key]>
|
|
380
|
+
}
|
|
381
|
+
/**
|
|
382
|
+
* @example
|
|
383
|
+
* ```
|
|
384
|
+
* interface Temp { a: string | null, b: number, c?: boolean }
|
|
385
|
+
* // Expect: { a: string, b: number, c?: boolean }
|
|
386
|
+
* type Example1 = NonNullableByKeys<Temp, 'a'>
|
|
387
|
+
* type Example2 = NonNullableByKeys<Temp, 'a' | 'b'>
|
|
388
|
+
*
|
|
389
|
+
* interface Temp { a: string | null, b: number, c?: boolean | null }
|
|
390
|
+
* // Expect: { a: string, b: number, c?: boolean }
|
|
391
|
+
* type Example3 = NonNullableByKeys<Temp, 'a' | 'c'>
|
|
392
|
+
* // Expect: { a: string | null, b: number, c?: boolean }
|
|
393
|
+
* type Example4 = NonNullableByKeys<Temp, 'c'>
|
|
394
|
+
* ```
|
|
395
|
+
*/
|
|
396
|
+
export type NonNullableByKeys<Target, Keys> = ObjectPrettify<
|
|
397
|
+
NonNullableAllKeys<Pick<Target, UnionIntersection<RequiredKeys<Target>, Keys>>>
|
|
398
|
+
& Pick<Target, UnionDifference<RequiredKeys<Target>, Keys>>
|
|
399
|
+
& Partial<NonNullableAllKeys<Pick<Target, UnionIntersection<OptionalKeys<Target>, Keys>>>>
|
|
400
|
+
& Pick<Target, UnionDifference<OptionalKeys<Target>, Keys>>
|
|
401
|
+
>
|
|
402
|
+
|
|
403
|
+
/**
|
|
404
|
+
* @example
|
|
405
|
+
* ```
|
|
406
|
+
* interface Temp { a: string | null | undefined, b: number, c?: boolean | null }
|
|
407
|
+
* // Expect: { a: string, b: number, c?: boolean }
|
|
408
|
+
* type Example1 = NonNilableAllKeys<Temp>
|
|
409
|
+
* ```
|
|
410
|
+
*/
|
|
411
|
+
export type NonNilableAllKeys<Target> = {
|
|
412
|
+
[Key in keyof Target]: NonNilable<Target[Key]>
|
|
413
|
+
}
|
|
414
|
+
/**
|
|
415
|
+
* @example
|
|
416
|
+
* ```
|
|
417
|
+
* interface Temp { a: string | null | undefined, b: number, c?: boolean }
|
|
418
|
+
* // Expect: { a: string, b: number, c?: boolean }
|
|
419
|
+
* type Example1 = NonNilableByKeys<Temp, 'a'>
|
|
420
|
+
* type Example2 = NonNilableByKeys<Temp, 'a' | 'b'>
|
|
421
|
+
*
|
|
422
|
+
* interface Temp { a: string | null | undefined, b: number, c?: boolean | null | undefined }
|
|
423
|
+
* // Expect: { a: string, b: number, c?: boolean }
|
|
424
|
+
* type Example3 = NonNilableByKeys<Temp, 'a' | 'c'>
|
|
425
|
+
* // Expect: { a: string | null | undefined, b: number, c?: boolean }
|
|
426
|
+
* type Example4 = NonNilableByKeys<Temp, 'c'>
|
|
427
|
+
* ```
|
|
428
|
+
*/
|
|
429
|
+
export type NonNilableByKeys<Target, Keys> = ObjectPrettify<
|
|
430
|
+
NonNilableAllKeys<Pick<Target, UnionIntersection<RequiredKeys<Target>, Keys>>>
|
|
431
|
+
& Pick<Target, UnionDifference<RequiredKeys<Target>, Keys>>
|
|
432
|
+
& Partial<NonNilableAllKeys<Pick<Target, UnionIntersection<OptionalKeys<Target>, Keys>>>>
|
|
433
|
+
& Pick<Target, UnionDifference<OptionalKeys<Target>, Keys>>
|
|
434
|
+
>
|
|
435
|
+
|
|
436
|
+
/**
|
|
437
|
+
* @example
|
|
438
|
+
* ```
|
|
439
|
+
* interface Temp { a?: string | undefined, b?: number, c?: boolean }
|
|
440
|
+
* // Expect: { readonly a: string | undefined, readonly b: number, readonly c: boolean }
|
|
441
|
+
* type Example1 = ReadonlyAllKeys<Temp>
|
|
442
|
+
* ```
|
|
443
|
+
*/
|
|
444
|
+
export type ReadonlyAllKeys<Target> = {
|
|
445
|
+
+readonly [Key in keyof Target]: Target[Key]
|
|
446
|
+
}
|
|
447
|
+
/**
|
|
448
|
+
* @example
|
|
449
|
+
* ```
|
|
450
|
+
* interface Temp { a?: string | undefined, b?: number, c?: boolean }
|
|
451
|
+
* // Expect: { readonly a: string | undefined, readonly b: number, readonly c: boolean }
|
|
452
|
+
* type Example1 = ReadonlyByKeys<Temp, 'a' | 'b' | 'c'>
|
|
453
|
+
* ```
|
|
454
|
+
*/
|
|
455
|
+
export type ReadonlyByKeys<Target, Keys> = ObjectPrettify<
|
|
456
|
+
ReadonlyAllKeys<Pick<Target, UnionIntersection<keyof Target, Keys>>> & Pick<Target, UnionDifference<keyof Target, Keys>>
|
|
457
|
+
>
|
|
458
|
+
|
|
459
|
+
/**
|
|
460
|
+
* @example
|
|
461
|
+
* ```
|
|
462
|
+
* interface Temp { readonly a?: string | undefined, readonly b?: number, readonly c?: boolean }
|
|
463
|
+
* // Expect: { a: string | undefined, b: number, c: boolean }
|
|
464
|
+
* type Example1 = WritableAllKeys<Temp>
|
|
465
|
+
* ```
|
|
466
|
+
*/
|
|
467
|
+
export type WritableAllKeys<Target> = {
|
|
468
|
+
-readonly [Key in keyof Target]: Target[Key]
|
|
469
|
+
}
|
|
470
|
+
/**
|
|
471
|
+
* @example
|
|
472
|
+
* ```
|
|
473
|
+
* interface Temp { readonly a?: string | undefined, readonly b?: number, readonly c?: boolean }
|
|
474
|
+
* // Expect: { a: string | undefined, b: number, c: boolean }
|
|
475
|
+
* type Example1 = WritableByKeys<Temp, 'a' | 'b' | 'c'>
|
|
476
|
+
* ```
|
|
477
|
+
*/
|
|
478
|
+
export type WritableByKeys<Target, Keys> = ObjectPrettify<
|
|
479
|
+
WritableAllKeys<Pick<Target, UnionIntersection<keyof Target, Keys>>> & Pick<Target, UnionDifference<keyof Target, Keys>>
|
|
480
|
+
>
|
|
481
|
+
|
|
482
|
+
/**
|
|
483
|
+
* @example
|
|
484
|
+
* ```
|
|
485
|
+
* interface Temp { a?: string | undefined, b?: number, c?: boolean }
|
|
486
|
+
* // Expect: { a: string | undefined, b: number, c: boolean }
|
|
487
|
+
* type Example1 = RequiredAllKeys<Temp>
|
|
488
|
+
* ```
|
|
489
|
+
*/
|
|
490
|
+
export type RequiredAllKeys<Target> = {
|
|
491
|
+
[Key in keyof Target]-?: Target[Key]
|
|
492
|
+
}
|
|
493
|
+
/**
|
|
494
|
+
* @example
|
|
495
|
+
* ```
|
|
496
|
+
* interface Temp { a?: string | undefined, b?: number, c?: boolean }
|
|
497
|
+
* // Expect: { a: string | undefined, b: number, c: boolean }
|
|
498
|
+
* type Example1 = RequiredByKeys<Temp, 'a' | 'b' | 'c'>
|
|
499
|
+
* ```
|
|
500
|
+
*/
|
|
501
|
+
export type RequiredByKeys<Target, Keys> = ObjectPrettify<
|
|
502
|
+
RequiredAllKeys<Pick<Target, UnionIntersection<keyof Target, Keys>>> & Pick<Target, UnionDifference<keyof Target, Keys>>
|
|
503
|
+
>
|
|
504
|
+
|
|
505
|
+
/**
|
|
506
|
+
* @example
|
|
507
|
+
* ```
|
|
508
|
+
* interface Temp { a: string | undefined, b: number, c?: boolean | undefined }
|
|
509
|
+
* // Expect: { a?: string | undefined, b?: number, c?: boolean | undefined }
|
|
510
|
+
* type Example1 = OptionalAllKeys<Temp>
|
|
511
|
+
* ```
|
|
512
|
+
*/
|
|
513
|
+
export type OptionalAllKeys<Target> = {
|
|
514
|
+
[Key in keyof Target]+?: Target[Key]
|
|
515
|
+
}
|
|
516
|
+
/**
|
|
517
|
+
* @example
|
|
518
|
+
* ```
|
|
519
|
+
* interface Temp { a: string | undefined, b: number, c?: boolean | undefined }
|
|
520
|
+
* // Expect: { a?: string | undefined, b?: number, c?: boolean }
|
|
521
|
+
* type Example1 = OptionalByKeys<Temp, 'a' | 'b' | 'c'>
|
|
522
|
+
* ```
|
|
523
|
+
*/
|
|
524
|
+
export type OptionalByKeys<Target, Keys> = ObjectPrettify<
|
|
525
|
+
OptionalAllKeys<Pick<Target, UnionIntersection<keyof Target, Keys>>> & Pick<Target, UnionDifference<keyof Target, Keys>>
|
|
526
|
+
>
|
|
527
|
+
|
|
528
|
+
/**
|
|
529
|
+
* Given a type `{ a?: string, b: number }`, return `{ a: string, b?: number }`.
|
|
530
|
+
*
|
|
531
|
+
* @example
|
|
532
|
+
* ```
|
|
533
|
+
* interface Temp { a: string, b?: number, c?: boolean }
|
|
534
|
+
* // Expect: { a?: string, b: number, c: boolean }
|
|
535
|
+
* type Example1 = ReverseOptional<Temp>
|
|
536
|
+
* ```
|
|
537
|
+
* @see {@link ReverseRequired}
|
|
538
|
+
* @see {@link https://stackoverflow.com/questions/57593022/reverse-required-and-optional-properties}
|
|
539
|
+
*/
|
|
540
|
+
export type ReverseOptional<Target> = ObjectPrettify<
|
|
541
|
+
Required<Pick<Target, OptionalKeys<Target>>> & OptionalAllKeys<Omit<Target, OptionalKeys<Target>>>
|
|
542
|
+
>
|
|
543
|
+
/**
|
|
544
|
+
* @see {@link ReverseOptional}
|
|
545
|
+
*/
|
|
546
|
+
export type ReverseRequired<Target> = ReverseOptional<Target>
|
|
547
|
+
|
|
548
|
+
/**
|
|
549
|
+
* @example
|
|
550
|
+
* ```
|
|
551
|
+
* interface Temp { a: string, b?: number, c?: boolean }
|
|
552
|
+
*
|
|
553
|
+
* // Expect: { a: string, b: number, c?: boolean }
|
|
554
|
+
* type Example1 = ReverseOptionalByKeys<Temp, 'b'>
|
|
555
|
+
* ```
|
|
556
|
+
*/
|
|
557
|
+
export type ReverseOptionalByKeys<Target, Keys extends keyof Target> = ObjectPrettify<
|
|
558
|
+
Omit<Target, Keys> & ReverseOptional<Pick<Target, Keys>>
|
|
559
|
+
>
|
|
560
|
+
/**
|
|
561
|
+
* @see {@link ReverseOptionalByKeys}
|
|
562
|
+
*/
|
|
563
|
+
export type ReverseRequiredByKeys<Target, Keys extends keyof Target> = ReverseOptionalByKeys<Target, Keys>
|
|
564
|
+
|
|
565
|
+
/**
|
|
566
|
+
* @example
|
|
567
|
+
* ```
|
|
568
|
+
* type Props = { name: string; age: number; visible: boolean };
|
|
569
|
+
* type DefaultProps = { age: number };
|
|
570
|
+
* // Expect: { age: number; }
|
|
571
|
+
* type Example1 = ObjectIntersection<Props, DefaultProps>
|
|
572
|
+
* ```
|
|
573
|
+
* @see {@link https://github.com/piotrwitek/utility-types/blob/master/src/mapped-types.ts}
|
|
574
|
+
*/
|
|
575
|
+
export type ObjectIntersection<T extends AnyHybridRecord, U extends AnyHybridRecord> = Pick<T, UnionIntersection<keyof T, keyof U>>
|
|
576
|
+
|
|
577
|
+
/**
|
|
578
|
+
* @example
|
|
579
|
+
* ```
|
|
580
|
+
* type Props = { name: string; age: number; visible: boolean };
|
|
581
|
+
* type DefaultProps = { age: number };
|
|
582
|
+
* // Expect: { name: string; visible: boolean; }
|
|
583
|
+
* type Example1 = ObjectDifference<Props, DefaultProps>
|
|
584
|
+
* ```
|
|
585
|
+
* @see {@link https://github.com/piotrwitek/utility-types/blob/master/src/mapped-types.ts}
|
|
586
|
+
*/
|
|
587
|
+
export type ObjectDifference<T extends AnyHybridRecord, U extends AnyHybridRecord> = Pick<T, UnionDifference<keyof T, keyof U>>
|
|
588
|
+
|
|
589
|
+
/**
|
|
590
|
+
* @example
|
|
591
|
+
* ```
|
|
592
|
+
* type Props = { name: string; age: number; visible: boolean };
|
|
593
|
+
* type DefaultProps = { age: number };
|
|
594
|
+
* // Expect: { name: string; visible: boolean; }
|
|
595
|
+
* type Example1 = ObjectComplement<Props, DefaultProps>
|
|
596
|
+
* ```
|
|
597
|
+
* @see {@link https://github.com/piotrwitek/utility-types/blob/master/src/mapped-types.ts}
|
|
598
|
+
*/
|
|
599
|
+
export type ObjectComplement<T extends SuperT, SuperT extends AnyHybridRecord> = Pick<T, UnionComplement<keyof T, keyof SuperT>>
|
|
600
|
+
|
|
601
|
+
/**
|
|
602
|
+
* @example
|
|
603
|
+
* ```
|
|
604
|
+
* interface PropsA { name: string, age: number, visible: boolean }
|
|
605
|
+
* interface PropsB { age: number, sex: string }
|
|
606
|
+
* // Expect: { name: string; visible: boolean; sex: string };
|
|
607
|
+
* type Example1 = ObjectSymmetricDifference<PropsA, PropsB>
|
|
608
|
+
* // Expect: 'name' | 'visible' | 'sex'
|
|
609
|
+
* type Example2 = keyof ObjectSymmetricDifference<PropsA, PropsB>
|
|
610
|
+
* ```
|
|
611
|
+
*/
|
|
612
|
+
export type ObjectSymmetricDifference<T extends AnyHybridRecord, U extends AnyHybridRecord> = ObjectPrettify<
|
|
613
|
+
ObjectDifference<T, U> & ObjectDifference<U, T>
|
|
614
|
+
>
|
|
615
|
+
|
|
616
|
+
/**
|
|
617
|
+
* @example
|
|
618
|
+
* ```
|
|
619
|
+
* interface Props { name: string, age: number, visible: boolean }
|
|
620
|
+
* interface NewProps { age: string, other: string }
|
|
621
|
+
* // Expect: { name: string; age: string; visible: boolean; }
|
|
622
|
+
* type Example1 = ObjectOverwrite<Props, NewProps>
|
|
623
|
+
* ```
|
|
624
|
+
* @see {@link https://github.com/piotrwitek/utility-types/blob/master/src/mapped-types.ts}
|
|
625
|
+
*/
|
|
626
|
+
export type ObjectOverwrite<Target extends AnyHybridRecord, Patch extends AnyHybridRecord> = ObjectPrettify<
|
|
627
|
+
ObjectDifference<Target, Patch> & ObjectIntersection<Patch, Target>
|
|
628
|
+
>
|
|
629
|
+
|
|
630
|
+
/**
|
|
631
|
+
* @example
|
|
632
|
+
* ```
|
|
633
|
+
* interface Props { name: string, age: number, visible: boolean }
|
|
634
|
+
* interface NewProps { age: string, other: string }
|
|
635
|
+
* // Expect: { name: string; age: string; visible: boolean; other: string; }
|
|
636
|
+
* type Example1 = ObjectAssign<Props, NewProps>
|
|
637
|
+
* ```
|
|
638
|
+
* @see {@link https://github.com/piotrwitek/utility-types/blob/master/src/mapped-types.ts}
|
|
639
|
+
*/
|
|
640
|
+
export type ObjectAssign<Target extends AnyHybridRecord, Patch extends AnyHybridRecord> = ObjectPrettify<
|
|
641
|
+
// ObjectDifference<Target, Patch> & ObjectIntersection<Patch, Target> & ObjectDifference<Patch, Target>
|
|
642
|
+
Omit<Target, keyof Patch> & Patch
|
|
643
|
+
>
|
|
644
|
+
/**
|
|
645
|
+
* Alias for `ObjectAssign`, defined for semantic of `ObjectMergeN`.
|
|
646
|
+
* @see {@link ObjectAssign}
|
|
647
|
+
*/
|
|
648
|
+
export type ObjectMerge<Target extends AnyHybridRecord, Patch extends AnyHybridRecord> = ObjectAssign<Target, Patch>
|
|
649
|
+
|
|
650
|
+
type InternalObjectMergeN<Targets extends AnyHybridRecord[], Result extends AnyHybridRecord> = Targets extends [infer Head, ...infer Tail] ?
|
|
651
|
+
InternalObjectMergeN<Tail extends AnyHybridRecord[] ? Tail : [], ObjectMerge<Result, Head extends AnyHybridRecord ? Head : {}>> : Result
|
|
652
|
+
/**
|
|
653
|
+
* @example
|
|
654
|
+
* ```
|
|
655
|
+
* interface a { a: string }
|
|
656
|
+
* interface b { readonly b: string }
|
|
657
|
+
* interface c { c?: string }
|
|
658
|
+
* // Expect: { a: string; readonly b: string; c?: string; }
|
|
659
|
+
* type Example1 = ObjectMergeN<[a, b, c]>
|
|
660
|
+
* ```
|
|
661
|
+
*/
|
|
662
|
+
export type ObjectMergeN<Targets extends AnyHybridRecord[]> = ObjectPrettify<InternalObjectMergeN<Targets, {}>>
|
|
663
|
+
|
|
664
|
+
/**
|
|
665
|
+
* @example
|
|
666
|
+
* ```
|
|
667
|
+
* interface Props { name: string, age: number, visible: boolean }
|
|
668
|
+
* // Expect: { name: string; } | { age: number; } | { visible: boolean; }
|
|
669
|
+
* type UnionizedType = ObjectUnionize<Props>
|
|
670
|
+
* ```
|
|
671
|
+
* @see {@link https://github.com/piotrwitek/utility-types/blob/master/src/mapped-types.ts}
|
|
672
|
+
*/
|
|
673
|
+
export type ObjectUnionize<Target extends AnyHybridRecord> = {
|
|
674
|
+
[Key in keyof Target]: { [Q in Key]: Target[Key] };
|
|
675
|
+
}[keyof Target]
|
|
676
|
+
|
|
677
|
+
/**
|
|
678
|
+
* @example
|
|
679
|
+
* ```
|
|
680
|
+
* interface Temp {
|
|
681
|
+
* readonly grandpa: {
|
|
682
|
+
* readonly name: string
|
|
683
|
+
* father?: {
|
|
684
|
+
* readonly name?: string
|
|
685
|
+
* son: {
|
|
686
|
+
* readonly name?: string
|
|
687
|
+
* }
|
|
688
|
+
* }
|
|
689
|
+
* }
|
|
690
|
+
* }
|
|
691
|
+
* // Expect: { grandpa?: { name?: string, father?: { name?: string, son?: { name?: string } } } }
|
|
692
|
+
* type Example1 = ObjectDeepWritable<Temp>
|
|
693
|
+
* ```
|
|
694
|
+
*/
|
|
695
|
+
export type ObjectDeepWritable<Target extends AnyStringRecord> = {
|
|
696
|
+
-readonly [Key in keyof Target]: Target[Key] extends (AnyStringRecord | undefined) ?
|
|
697
|
+
ObjectDeepWritable<NonUndefinedable<Target[Key]>> : Target[Key];
|
|
698
|
+
}
|
|
699
|
+
|
|
700
|
+
/**
|
|
701
|
+
* @example
|
|
702
|
+
* ```
|
|
703
|
+
* interface Temp {
|
|
704
|
+
* grandpa: {
|
|
705
|
+
* name: string
|
|
706
|
+
* father?: {
|
|
707
|
+
* name?: string
|
|
708
|
+
* son: {
|
|
709
|
+
* name?: string
|
|
710
|
+
* }
|
|
711
|
+
* }
|
|
712
|
+
* }
|
|
713
|
+
* }
|
|
714
|
+
* // Expect: { readonly grandpa?: {
|
|
715
|
+
* // readonly name?: string, readonly father?: { readonly name?: string, readonly son?: { readonly name?: string } }
|
|
716
|
+
* // } }
|
|
717
|
+
* type Example1 = ObjectDeepReadonly<Temp>
|
|
718
|
+
* ```
|
|
719
|
+
*/
|
|
720
|
+
export type ObjectDeepReadonly<Target extends AnyStringRecord> = {
|
|
721
|
+
+readonly [Key in keyof Target]: Target[Key] extends (AnyStringRecord | undefined) ?
|
|
722
|
+
ObjectDeepReadonly<NonUndefinedable<Target[Key]>> : Target[Key];
|
|
723
|
+
}
|
|
724
|
+
|
|
725
|
+
/**
|
|
726
|
+
* @example
|
|
727
|
+
* ```
|
|
728
|
+
* interface Temp {
|
|
729
|
+
* grandpa: {
|
|
730
|
+
* name: string
|
|
731
|
+
* father?: {
|
|
732
|
+
* name?: string
|
|
733
|
+
* son: {
|
|
734
|
+
* name?: string
|
|
735
|
+
* }
|
|
736
|
+
* }
|
|
737
|
+
* }
|
|
738
|
+
* }
|
|
739
|
+
* // Expect: { grandpa: { name: string, father: { name: string, son: { name: string } } } }
|
|
740
|
+
* type Example1 = ObjectDeepRequired<Temp>
|
|
741
|
+
* ```
|
|
742
|
+
*/
|
|
743
|
+
export type ObjectDeepRequired<Target extends AnyStringRecord> = {
|
|
744
|
+
[Key in keyof Target]-?: Target[Key] extends (AnyStringRecord | undefined) ?
|
|
745
|
+
ObjectDeepRequired<NonUndefinedable<Target[Key]>> : Target[Key];
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
/**
|
|
749
|
+
* @example
|
|
750
|
+
* ```
|
|
751
|
+
* interface Temp {
|
|
752
|
+
* grandpa: {
|
|
753
|
+
* name: string
|
|
754
|
+
* father?: {
|
|
755
|
+
* name?: string
|
|
756
|
+
* son: {
|
|
757
|
+
* name?: string
|
|
758
|
+
* }
|
|
759
|
+
* }
|
|
760
|
+
* }
|
|
761
|
+
* }
|
|
762
|
+
* // Expect: { grandpa?: { name?: string, father?: { name?: string, son?: { name?: string } } } }
|
|
763
|
+
* type Example1 = ObjectDeepOptional<Temp>
|
|
764
|
+
* ```
|
|
765
|
+
*/
|
|
766
|
+
export type ObjectDeepOptional<Target extends AnyStringRecord> = {
|
|
767
|
+
[Key in keyof Target]+?: Target[Key] extends (AnyStringRecord | undefined) ?
|
|
768
|
+
ObjectDeepOptional<NonUndefinedable<Target[Key]>> : Target[Key];
|
|
769
|
+
}
|
|
770
|
+
|
|
771
|
+
// ============================================================================
|
|
772
|
+
// Conversion
|
|
773
|
+
// ============================================================================
|
|
774
|
+
|
|
775
|
+
/**
|
|
776
|
+
* Extract method signature as a standalone function.
|
|
777
|
+
*
|
|
778
|
+
* @example
|
|
779
|
+
* ```
|
|
780
|
+
* type Obj = { method(a: number, b: string): boolean }
|
|
781
|
+
* // Expect: (a: number, b: string) => boolean
|
|
782
|
+
* type Example1 = ObjectToFunction<Obj, 'method'>
|
|
783
|
+
* ```
|
|
784
|
+
*/
|
|
785
|
+
export type ObjectToFunction<T, Key extends keyof T> =
|
|
786
|
+
T[Key] extends (...args: infer P) => infer R
|
|
787
|
+
? (...args: P) => R
|
|
788
|
+
: never
|