@aryaemami59/tsconfig 0.0.5 → 0.0.7

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.
@@ -0,0 +1,468 @@
1
+ /**
2
+ * Any function with **`unknown`** arguments.
3
+ * You probably want this instead of {@linkcode Function}.
4
+ *
5
+ * @example
6
+ * <caption>Basic usage</caption>
7
+ *
8
+ * ```ts
9
+ * const fn = ((...args) => args.length) satisfies UnknownFunction;
10
+ * ```
11
+ *
12
+ * @since v0.0.6 of **`@aryaemami59/tsconfig`**
13
+ * @internal
14
+ */
15
+ export type UnknownFunction = (...args: unknown[]) => unknown
16
+
17
+ /**
18
+ * An alias for **`NonNullable<unknown>`**, which represents any value that is
19
+ * **not** `null` or `undefined`. This is primarily a semantic helper used to
20
+ * distinguish between:
21
+ *
22
+ * - the empty object type **`{}`**, which accepts all non-nullish values but
23
+ * conveys an “object-like” intent, and
24
+ * - **`NonNullable<unknown>`**, which explicitly means “any non-nullish value,”
25
+ * including primitives.
26
+ *
27
+ * @example
28
+ * <caption>Basic usage</caption>
29
+ *
30
+ * ```ts
31
+ * // ✅ OK
32
+ * const a = 123 as const satisfies AnyNonNullishValue;
33
+ * const b = "hello" as const satisfies AnyNonNullishValue;
34
+ * const c = true as const satisfies AnyNonNullishValue;
35
+ * const d = {} as const satisfies AnyNonNullishValue;
36
+ * const e = [] as const satisfies AnyNonNullishValue;
37
+ * const f = (() => {
38
+ * console.log("hi");
39
+ * }) satisfies AnyNonNullishValue;
40
+ * const g = Symbol("x") satisfies AnyNonNullishValue;
41
+ *
42
+ * // ❌ Error
43
+ * // @ts-expect-error
44
+ * const h = null satisfies AnyNonNullishValue;
45
+ * // @ts-expect-error
46
+ * const i = undefined satisfies AnyNonNullishValue;
47
+ * ```
48
+ *
49
+ * @since v0.0.6 of **`@aryaemami59/tsconfig`**
50
+ * @internal
51
+ */
52
+ export type AnyNonNullishValue = NonNullable<unknown>
53
+
54
+ /**
55
+ * Useful to flatten the type output to improve type hints shown in editors.
56
+ * And also to transform an interface into a type to aide with assignability.
57
+ *
58
+ * @example
59
+ * <caption>Basic usage</caption>
60
+ *
61
+ * ```ts
62
+ * interface SomeInterface {
63
+ * bar?: string;
64
+ * baz: number | undefined;
65
+ * foo: number;
66
+ * }
67
+ *
68
+ * type SomeType = {
69
+ * bar?: string;
70
+ * baz: number | undefined;
71
+ * foo: number;
72
+ * };
73
+ *
74
+ * const literal = {
75
+ * bar: "hello",
76
+ * baz: 456,
77
+ * foo: 123,
78
+ * } as const satisfies SomeType satisfies SomeInterface;
79
+ *
80
+ * const someType: SomeType = literal;
81
+ * const someInterface: SomeInterface = literal;
82
+ *
83
+ * function fn(object: Record<string, unknown>): void {
84
+ * console.log(object);
85
+ * };
86
+ *
87
+ * fn(literal); // ✅ Good: literal object type is sealed
88
+ * fn(someType); // ✅ Good: type is sealed
89
+ * // @ts-expect-error
90
+ * fn(someInterface); // ❌ Error: Index signature for type "string" is missing in type "someInterface". Because `interface` can be re-opened
91
+ * fn(someInterface as Simplify<SomeInterface>); // ✅ Good: transform an `interface` into a `type`
92
+ * ```
93
+ *
94
+ * @template BaseType - The type to simplify.
95
+ *
96
+ * @see {@link https://github.com/sindresorhus/type-fest/blob/2300245cb6f0b28ee36c2bb852ade872254073b8/source/simplify.d.ts Source}
97
+ * @see {@link https://github.com/microsoft/TypeScript/issues/15300 | TypeScript Issue}
98
+ * @since v0.0.6 of **`@aryaemami59/tsconfig`**
99
+ * @internal
100
+ */
101
+ export type Simplify<BaseType> = BaseType extends BaseType
102
+ ? BaseType extends UnknownFunction
103
+ ? BaseType
104
+ : AnyNonNullishValue & {
105
+ [KeyType in keyof BaseType]: BaseType[KeyType]
106
+ }
107
+ : never
108
+
109
+ /**
110
+ * Omits keys from a type, **distributing** the operation over a union.
111
+ * TypeScript's {@linkcode Omit} does **not** distribute over unions,
112
+ * which can lead to the erasure of unique properties from union members
113
+ * when omitting keys. This causes the resulting type to retain only
114
+ * properties common to all union members, making it impossible to access
115
+ * member-specific properties after using {@linkcode Omit}.
116
+ * In other words, using {@linkcode Omit} on a union merges its members into
117
+ * a less specific type, breaking type narrowing and property access based
118
+ * on discriminants. This utility solves that limitation by applying
119
+ * {@linkcode Omit} distributively to each union member.
120
+ *
121
+ * @example
122
+ * <caption>Demonstrating `Omit` vs `DistributedOmit`</caption>
123
+ *
124
+ * ```ts
125
+ * type A = {
126
+ * a: number;
127
+ * discriminant: "A";
128
+ * foo: string;
129
+ * };
130
+ *
131
+ * type B = {
132
+ * b: string;
133
+ * discriminant: "B";
134
+ * foo: string;
135
+ * };
136
+ *
137
+ * type Union = A | B;
138
+ *
139
+ * const omittedUnion: Omit<Union, "foo"> = {
140
+ * discriminant: "A",
141
+ * };
142
+ *
143
+ * if (omittedUnion.discriminant === "A") {
144
+ * // We would like to narrow `omittedUnion`'s type to `A` here,
145
+ * // but we can't because `Omit` doesn't distribute over unions.
146
+ *
147
+ * // @ts-expect-error
148
+ * omittedUnion.a;
149
+ * // => ❌ Error: Property 'a' does not exist on type '{ discriminant: "A" | "B" }'
150
+ * }
151
+ *
152
+ * const distributedOmittedUnion: DistributedOmit<Union, "foo"> = {
153
+ * a: 123,
154
+ * discriminant: "A",
155
+ * };
156
+ *
157
+ * if (distributedOmittedUnion.discriminant === "A") {
158
+ * // We can successfully narrow `distributedOmittedUnion`'s type to `A` here,
159
+ * // because `DistributedOmit` distributes over unions.
160
+ *
161
+ * distributedOmittedUnion.a;
162
+ * // => ✅ OK
163
+ * }
164
+ * ```
165
+ *
166
+ * @template ObjectType - The base object or union type to omit properties from.
167
+ * @template KeyType - The keys of {@linkcode ObjectType} to omit.
168
+ * @since v0.0.6 of **`@aryaemami59/tsconfig`**
169
+ * @internal
170
+ */
171
+ export type DistributedOmit<
172
+ ObjectType,
173
+ KeyType extends keyof ObjectType,
174
+ > = ObjectType extends unknown ? Omit<ObjectType, KeyType> : never
175
+
176
+ /**
177
+ * Picks keys from a type, **distributing** the operation over a union.
178
+ * TypeScript's {@linkcode Pick} does **not** distribute over unions,
179
+ * which can lead to the erasure of unique properties from union members
180
+ * when picking keys. This causes the resulting type to retain only
181
+ * properties common to all union members, making it impossible to access
182
+ * member-specific properties after using {@linkcode Pick}.
183
+ * In other words, using {@linkcode Pick} on a union merges its members into
184
+ * a less specific type, breaking type narrowing and property access based
185
+ * on discriminants. This utility solves that limitation by applying
186
+ * {@linkcode Pick} distributively to each union member.
187
+ *
188
+ * @example
189
+ * <caption>Demonstrating `Pick` vs `DistributedPick`</caption>
190
+ *
191
+ * ```ts
192
+ * type A = {
193
+ * discriminant: "A";
194
+ * extraneous: boolean;
195
+ * foo: {
196
+ * bar: string;
197
+ * };
198
+ * };
199
+ *
200
+ * type B = {
201
+ * discriminant: "B";
202
+ * extraneous: boolean;
203
+ * foo: {
204
+ * baz: string;
205
+ * };
206
+ * };
207
+ *
208
+ * // Notice that `foo.bar` exists in `A` but not in `B`.
209
+ *
210
+ * type Union = A | B;
211
+ *
212
+ * const pickedUnion: Pick<Union, "discriminant" | "foo"> = {
213
+ * discriminant: "A",
214
+ * foo: {
215
+ * bar: "",
216
+ * },
217
+ * };
218
+ *
219
+ * if (pickedUnion.discriminant === "A") {
220
+ * // We would like to narrow to `A` here,
221
+ * // but we can't because `Pick` doesn't distribute over unions.
222
+ *
223
+ * // @ts-expect-error
224
+ * pickedUnion.foo.bar;
225
+ * //=> ❌ Error: Property 'bar' does not exist on type '{ bar: string; } | { baz: string; }'.
226
+ *
227
+ * // @ts-expect-error
228
+ * pickedUnion.extraneous;
229
+ * //=> ❌ Error: Property 'extraneous' does not exist on type 'Pick<Union, "discriminant" | "foo">'.
230
+ *
231
+ * // @ts-expect-error
232
+ * pickedUnion.foo.baz;
233
+ * // => ❌ Error: Property 'baz' does not exist on type '{ bar: string; } | { baz: string; }'.
234
+ * }
235
+ *
236
+ * const distributedPickedUnion: DistributedPick<Union, "discriminant" | "foo"> = {
237
+ * discriminant: "A",
238
+ * foo: {
239
+ * bar: "",
240
+ * },
241
+ * };
242
+ *
243
+ * if (distributedPickedUnion.discriminant === "A") {
244
+ * // Narrowing works correctly because the pick is applied per union member.
245
+ *
246
+ * distributedPickedUnion.foo.bar;
247
+ * // => ✅ OK
248
+ *
249
+ * // @ts-expect-error
250
+ * distributedPickedUnion.extraneous;
251
+ * //=> ❌ Error: Property 'extraneous' does not exist on type 'Pick<A, "discriminant" | "foo">'.
252
+ *
253
+ * // @ts-expect-error
254
+ * distributedPickedUnion.foo.baz;
255
+ * //=> ❌ Error: Property 'baz' does not exist on type '{ bar: string; }'.
256
+ * }
257
+ * ```
258
+ *
259
+ * @template ObjectType - The base object or union type to pick properties from.
260
+ * @template KeyType - The keys of {@linkcode ObjectType} to pick.
261
+ * @since v0.0.6 of **`@aryaemami59/tsconfig`**
262
+ * @internal
263
+ */
264
+ export type DistributedPick<
265
+ ObjectType,
266
+ KeyType extends keyof ObjectType,
267
+ > = ObjectType extends unknown ? Pick<ObjectType, KeyType> : never
268
+
269
+ /**
270
+ * A stricter version of
271
+ * {@linkcode Extract | Extract<BaseType, TypeToExtract>} that ensures
272
+ * every member of {@linkcode TypeToExtract} can successfully extract
273
+ * something from {@linkcode BaseType}.
274
+ *
275
+ * @example
276
+ * <caption>Basic Usage</caption>
277
+ *
278
+ * ```ts
279
+ * type Example = ExtractStrict<"l" | "m" | "s" | "xl" | "xs", "s" | "xs">;
280
+ * //=> "s" | "xs"
281
+ * ```
282
+ *
283
+ * @template BaseType - The base type to extract from.
284
+ * @template TypeToExtract - The type(s) to extract from {@linkcode BaseType}.
285
+ * @since v0.0.6 of **`@aryaemami59/tsconfig`**
286
+ * @internal
287
+ */
288
+ export type ExtractStrict<
289
+ BaseType,
290
+ TypeToExtract extends [TypeToExtract] extends [
291
+ TypeToExtract extends unknown
292
+ ? Extract<BaseType, TypeToExtract> extends never
293
+ ? never
294
+ : TypeToExtract
295
+ : never,
296
+ ]
297
+ ? unknown
298
+ : BaseType,
299
+ > = Extract<BaseType, TypeToExtract>
300
+
301
+ /**
302
+ * A stricter version of
303
+ * {@linkcode Exclude | Exclude<BaseType, TypesToExclude>} that ensures
304
+ * every member of {@linkcode TypesToExclude} can successfully exclude
305
+ * something from {@linkcode BaseType}.
306
+ *
307
+ * @example
308
+ * <caption>Basic Usage</caption>
309
+ *
310
+ * ```ts
311
+ * type Example = ExcludeStrict<"l" | "m" | "s" | "xl" | "xs", "s" | "xs">;
312
+ * //=> "l" | "m" | "xl"
313
+ * ```
314
+ *
315
+ * @template BaseType - The base type to exclude from.
316
+ * @template TypesToExclude - The type(s) to exclude from {@linkcode BaseType}.
317
+ * @since v0.0.6 of **`@aryaemami59/tsconfig`**
318
+ * @internal
319
+ */
320
+ export type ExcludeStrict<
321
+ BaseType,
322
+ TypesToExclude extends [TypesToExclude] extends [
323
+ TypesToExclude extends unknown
324
+ ? [BaseType] extends [Exclude<BaseType, TypesToExclude>]
325
+ ? never
326
+ : TypesToExclude
327
+ : never,
328
+ ]
329
+ ? unknown
330
+ : BaseType,
331
+ > = Exclude<BaseType, TypesToExclude>
332
+
333
+ /**
334
+ * Convert a string literal to kebab-case.
335
+ *
336
+ * @example
337
+ * <caption>Basic usage</caption>
338
+ *
339
+ * ```ts
340
+ * const someVariable = "foo-bar" as const satisfies KebabCase<"fooBar">;
341
+ * ```
342
+ *
343
+ * @template StringType - The string literal type to convert to kebab-case.
344
+ * @template FirstRun - Internal helper to avoid prefixing the first character with a hyphen.
345
+ * @since v0.0.6 of **`@aryaemami59/tsconfig`**
346
+ * @internal
347
+ * @see {@link https://stackoverflow.com/a/66140779 Source}
348
+ */
349
+ export type KebabCase<
350
+ StringType extends string,
351
+ FirstRun extends boolean = true,
352
+ > = StringType extends `${infer FirstCharacter}${infer RemainingString}`
353
+ ? `${FirstCharacter extends Lowercase<FirstCharacter>
354
+ ? FirstCharacter extends `${number}`
355
+ ? RemainingString extends `${number}`
356
+ ? '-'
357
+ : ''
358
+ : ''
359
+ : FirstRun extends true
360
+ ? ''
361
+ : '-'}${Lowercase<FirstCharacter>}${KebabCase<RemainingString, false>}`
362
+ : StringType
363
+
364
+ /**
365
+ * Extracts only the **lowercase** string literal members from a given string
366
+ * literal type. This is especially useful when you have a union that mixes
367
+ * lowercase and capitalized variants and you want to keep only the canonical
368
+ * lowercase ones.
369
+ *
370
+ * @example
371
+ * <caption>Basic usage</caption>
372
+ *
373
+ * ```ts
374
+ * type ModuleResolution =
375
+ * | "bundler"
376
+ * | "Bundler"
377
+ * | "classic"
378
+ * | "Classic"
379
+ * | "node"
380
+ * | "Node"
381
+ * | "node10"
382
+ * | "Node10"
383
+ * | "node16"
384
+ * | "Node16"
385
+ * | "nodenext"
386
+ * | "NodeNext";
387
+ *
388
+ * type LowercaseModuleResolution = ExtractLowercase<ModuleResolution>;
389
+ * // ^? "bundler" | "classic" | "node" | "node10" | "node16" | "nodenext"
390
+ * ```
391
+ *
392
+ * @template StringType - A string literal type to filter.
393
+ * @see {@linkcode Lowercase} - The built-in utility used to test lowercase values.
394
+ * @since v0.0.6 of **`@aryaemami59/tsconfig`**
395
+ * @internal
396
+ */
397
+ export type ExtractLowercase<StringType extends string> =
398
+ StringType extends Lowercase<StringType> ? StringType : never
399
+
400
+ /**
401
+ * Extracts only the **capitalized** (PascalCase-style) string literal members
402
+ * from a given string literal type. Each member of {@linkcode StringType} is
403
+ * evaluated using TypeScript's {@linkcode Capitalize} helper, and only those
404
+ * that are already capitalized are retained. All others resolve to `never`,
405
+ * effectively filtering them out of a union.
406
+ *
407
+ * @example
408
+ * <caption>Basic usage</caption>
409
+ *
410
+ * ```ts
411
+ * type ModuleResolution =
412
+ * | "bundler"
413
+ * | "Bundler"
414
+ * | "classic"
415
+ * | "Classic"
416
+ * | "node"
417
+ * | "Node"
418
+ * | "node10"
419
+ * | "Node10"
420
+ * | "node16"
421
+ * | "Node16"
422
+ * | "nodenext"
423
+ * | "NodeNext";
424
+ *
425
+ * type CapitalizedModuleResolution = ExtractCapitalized<ModuleResolution>;
426
+ * // ^? "Bundler" | "Classic" | "Node" | "Node10" | "Node16" | "NodeNext"
427
+ * ```
428
+ *
429
+ * @template StringType - The string literal type to filter.
430
+ * @see {@linkcode Capitalize} - The built-in utility used to test capitalization.
431
+ * @since v0.0.6 of **`@aryaemami59/tsconfig`**
432
+ * @internal
433
+ */
434
+ export type ExtractCapitalized<StringType extends string> =
435
+ StringType extends Capitalize<StringType> ? StringType : never
436
+
437
+ /**
438
+ * Produces a **widened string type** that still preserves autocomplete for the
439
+ * provided string literal union. Given a union of string literals, this utility
440
+ * returns a type that:
441
+ *
442
+ * - retains all literal members of {@linkcode StringType}, and
443
+ * - widens the union to `string & AnyNonNullishValue` to allow arbitrary
444
+ * user-provided strings while still supporting IDE completions for the known
445
+ * literals.
446
+ *
447
+ * This pattern is commonly used in configuration APIs where known literal
448
+ * options are suggested but custom strings must also be allowed.
449
+ *
450
+ * @example
451
+ * <caption>Preserving autocomplete while allowing any string</caption>
452
+ *
453
+ * ```ts
454
+ * type JsxFactory = StringLiteralUnion<"React.createElement">;
455
+ * // ^? "React.createElement" | (string & {})
456
+ *
457
+ * const a = "React.createElement" as const satisfies JsxFactory; // ✅ OK — literal member
458
+ * const b = "h" as const satisfies JsxFactory; // ✅ OK — arbitrary string allowed
459
+ * ```
460
+ *
461
+ * @template StringType - The string literal union to widen.
462
+ * @since v0.0.6 of **`@aryaemami59/tsconfig`**
463
+ * @internal
464
+ */
465
+ export type StringLiteralUnion<StringType extends string> =
466
+ StringType extends StringType
467
+ ? (string & AnyNonNullishValue) | StringType
468
+ : never