|
1 | 1 | /**
|
2 |
| -Extract members of a union type `Type` based on the |
3 |
| -fields in the given union type `Union`, where each |
4 |
| -union member of `Union` is only allowed to be a subset |
5 |
| -of some union member of `Type`. |
| 2 | +A stricter version of {@link Extract<T, U>} that ensures every member of `U` can successfully extract something from `T`. |
6 | 3 |
|
7 |
| -Constraint: ∀ U ∈ Union, U ⊆ T, where T ∈ Type |
| 4 | +For example, `StrictExtract<string | number | boolean, number | bigint>` will error because `bigint` cannot extract anything from `string | number | boolean`. |
8 | 5 |
|
9 | 6 | @example
|
10 | 7 | ```
|
11 |
| -type Foo = { |
12 |
| - kind: 'foo'; |
13 |
| - a: string; |
14 |
| - b: string; |
15 |
| -}; |
| 8 | +// Valid Examples |
16 | 9 |
|
17 |
| -type Bar = { |
18 |
| - kind: 'bar'; |
19 |
| - a: string; |
20 |
| - b: number; |
21 |
| - c: boolean; |
22 |
| -}; |
| 10 | +type Example1 = ExtractStrict<{status: 'success'; data: string[]} | {status: 'error'; error: string}, {status: 'success'}>; |
| 11 | +//=> {status: 'success'; data: string[]} |
23 | 12 |
|
24 |
| -type Foobar = Foo | Bar; |
| 13 | +type Example2 = ExtractStrict<'xs' | 's' | 'm' | 'l' | 'xl', 'xs' | 's'>; |
| 14 | +//=> 'xs' | 's' |
25 | 15 |
|
26 |
| -type FoobarByA = ExtractStrict<Foobar, {a: string}>; |
27 |
| -// => Foobar |
28 |
| -
|
29 |
| -type OnlyFooByKind = ExtractStrict<Foobar, {kind: 'foo'}>; |
30 |
| -// => Foo |
| 16 | +type Example3 = ExtractStrict<{x: number; y: number} | [number, number], unknown[]>; |
| 17 | +//=> [number, number] |
| 18 | +``` |
31 | 19 |
|
32 |
| -type OnlyFooByB = ExtractStrict<Foobar, {b: string}>; |
33 |
| -// => Foo |
| 20 | +@example |
| 21 | +``` |
| 22 | +// Invalid Examples |
34 | 23 |
|
35 |
| -type OnlyBarByC = ExtractStrict<Foobar, {c: boolean}>; |
36 |
| -// => Bar |
| 24 | +// `'xxl'` cannot extract anything from `'xs' | 's' | 'm' | 'l' | 'xl'` |
| 25 | +type Example1 = ExtractStrict<'xs' | 's' | 'm' | 'l' | 'xl', 'xl' | 'xxl'>; |
| 26 | +// ~~~~~~~~~~~~ |
| 27 | +// Error: Type "'xl' | 'xxl'" does not satisfy the constraint 'never'. |
37 | 28 |
|
38 |
| -type InvalidUnionForType = ExtractStrict<Foobar, {d: string}>; |
39 |
| -// => Error: |
40 |
| -// Types of property 'd' are incompatible. |
41 |
| -// Type 'string' is not assignable to type 'never'. |
| 29 | +// `unknown[]` cannot extract anything from `{x: number; y: number} | {x: string; y: string}` |
| 30 | +type Example2 = ExtractStrict<{x: number; y: number} | {x: string; y: string}, unknown[]>; |
| 31 | +// ~~~~~~~~~ |
| 32 | +// Error: Type 'unknown[]' does not satisfy the constraint 'never'. |
42 | 33 | ```
|
| 34 | +
|
43 | 35 | @category Improved Builtin
|
44 | 36 | */
|
45 | 37 | export type ExtractStrict<
|
46 |
| - Type, |
47 |
| - Union extends [Union] extends [ |
48 |
| - // Ensure every member of `Union` extracts something from `Type` |
49 |
| - Union extends unknown ? (Extract<Type, Union> extends never ? never : Union) : never, |
| 38 | + T, |
| 39 | + U extends [U] extends [ |
| 40 | + // Ensure every member of `U` extracts something from `T` |
| 41 | + U extends unknown ? (Extract<T, U> extends never ? never : U) : never, |
50 | 42 | ]
|
51 | 43 | ? unknown
|
52 | 44 | : never,
|
53 |
| -> = Extract<Type, Union>; |
| 45 | +> = Extract<T, U>; |
0 commit comments