-
-
Notifications
You must be signed in to change notification settings - Fork 11
/
assignable.ts
101 lines (97 loc) · 3.22 KB
/
assignable.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
import type { $Any } from '../any/any.js'
import type { $Never } from '../never/never.js'
import type { $SpecialType } from '../type_plus/$special_type.js'
import type { $DistributiveDefault, $DistributiveOptions } from '../type_plus/branch/$distributive.js'
import type { $InputOptions } from '../type_plus/branch/$input_options.js'
import type { $IsDistributive } from '../type_plus/branch/$is_distributive.js'
import type { $ResolveBranch } from '../type_plus/branch/$resolve_branch.js'
import type { $Else, $SelectionBranch, $SelectionPredicate, $Then } from '../type_plus/branch/$selection.js'
import type { $SelectionOptions } from '../type_plus/branch/$selection_options.js'
import type { $Unknown } from '../unknown/unknown.js'
/**
* 🎭 *predicate*
*
* Validate if `A` is assignable to `B`.
*
* @example
* ```ts
* type R = Assignable<any, any> // true
* type R = Assignable<any, 1> // true
* type R = Assignable<unknown, unknown> // true
* type R = Assignable<never, never> // true
* type R = Assignable<1, 1> // true
* type R = Assignable<'a', 'a'> // true
* type R = Assignable<'a', 'b'> // false
* type R = Assignable<'a', string> // true
* ```
*
* 🔢 *customize*
*
* Filter to ensure `A` is assignable to `B`.
*
* @example
* ```ts
* type R = Assignable<any, any, { selection: 'filter' }> // any
* type R = Assignable<1, number, { selection: 'filter' }> // 1
* ```
*
* 🔢 *customize*
*
* Use unique branch identifiers to allow precise processing of the result.
*
* @example
* ```ts
* type R = Assignable<any, any, Assignable.$Branch> // $Then
* ```
*
* 🔢 *customize*
*
* Override special types branch.
*
* @example
* ```ts
* type R = Assignable<any, any, { $any: 1 }> // 1
* type R = Assignable<unknown, any, { $unknown: 1 }> // 1
* type R = Assignable<never, any, { $never: 1 }> // 1
* ```
*/
export type Assignable<A, B, $O extends Assignable.$Options = {}> = $SpecialType<
B,
{
$any: $ResolveBranch<A, $O, [0 extends 1 & A ? $Any : unknown, $Then]>
$unknown: $ResolveBranch<A, $O, [[A, unknown] extends [unknown, A] ? $Unknown : unknown, $Then]>
$never: $ResolveBranch<A, $O, [A, never] extends [never, A] ? [$Never, $Then] : [$Else]>
$else: $SpecialType<
A,
{
$any: $ResolveBranch<A, $O, [$Any, $Then]>
$unknown: $ResolveBranch<A, $O, [$Unknown, $Then]>
$never: $ResolveBranch<A, $O, [$Never, $Then]>
$else: Assignable.$<A, B, $O>
}
>
}
>
export namespace Assignable {
export type $Options = $SelectionOptions & $DistributiveOptions & $InputOptions<$Any | $Unknown | $Never>
export type $Default = $SelectionPredicate & $DistributiveDefault
export type $Branch<$O extends $DistributiveOptions = {}> = $SelectionBranch & $O
/**
* 🧰 *type util*
*
* Validate if `A` is assignable to `B`.
*
* This is the internal logic of `Assignable`.
* It does not check against special types.
*
* It is suitable for building custom types.
*/
export type $<A, B, $O extends $UtilOptions> = $IsDistributive<
$O,
{
$then: A extends B ? $ResolveBranch<A, $O, [$Then]> : $ResolveBranch<A, $O, [$Else]>
$else: [A] extends [B] ? $ResolveBranch<A, $O, [$Then]> : $ResolveBranch<A, $O, [$Else]>
}
>
export type $UtilOptions = $SelectionOptions & $DistributiveOptions
}