/
callOfConditionalTypeWithConcreteBranches.types
111 lines (95 loc) · 3.04 KB
/
callOfConditionalTypeWithConcreteBranches.types
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
102
103
104
105
106
107
108
109
110
111
=== tests/cases/compiler/callOfConditionalTypeWithConcreteBranches.ts ===
type Q<T> = number extends T ? (n: number) => void : never;
>Q : Q<T>
>n : number
function fn<T>(arg: Q<T>) {
>fn : <T>(arg: Q<T>) => void
>arg : Q<T>
// Expected: OK
// Actual: Cannot convert 10 to number & T
arg(10);
>arg(10) : void
>arg : Q<T>
>10 : 10
}
// Legal invocations are not problematic
fn<string | number>(m => m.toFixed());
>fn<string | number>(m => m.toFixed()) : void
>fn : <T>(arg: Q<T>) => void
>m => m.toFixed() : (m: number) => string
>m : number
>m.toFixed() : string
>m.toFixed : (fractionDigits?: number) => string
>m : number
>toFixed : (fractionDigits?: number) => string
fn<number>(m => m.toFixed());
>fn<number>(m => m.toFixed()) : void
>fn : <T>(arg: Q<T>) => void
>m => m.toFixed() : (m: number) => string
>m : number
>m.toFixed() : string
>m.toFixed : (fractionDigits?: number) => string
>m : number
>toFixed : (fractionDigits?: number) => string
// Ensure the following real-world example that relies on substitution still works
type ExtractParameters<T> = "parameters" extends keyof T
>ExtractParameters : ExtractParameters<T>
// The above allows "parameters" to index `T` since all later
// instances are actually implicitly `"parameters" & keyof T`
? {
[K in keyof T["parameters"]]: T["parameters"][K];
}[keyof T["parameters"]]
: {};
// Original example, but with inverted variance
type Q2<T> = number extends T ? (cb: (n: number) => void) => void : never;
>Q2 : Q2<T>
>cb : (n: number) => void
>n : number
function fn2<T>(arg: Q2<T>) {
>fn2 : <T>(arg: Q2<T>) => void
>arg : Q2<T>
function useT(_arg: T): void {}
>useT : (_arg: T) => void
>_arg : T
// Expected: OK
arg(arg => useT(arg));
>arg(arg => useT(arg)) : void
>arg : Q2<T>
>arg => useT(arg) : (arg: number) => void
>arg : number
>useT(arg) : void
>useT : (_arg: T) => void
>arg : number
}
// Legal invocations are not problematic
fn2<string | number>(m => m(42));
>fn2<string | number>(m => m(42)) : void
>fn2 : <T>(arg: Q2<T>) => void
>m => m(42) : (m: (n: number) => void) => void
>m : (n: number) => void
>m(42) : void
>m : (n: number) => void
>42 : 42
fn2<number>(m => m(42));
>fn2<number>(m => m(42)) : void
>fn2 : <T>(arg: Q2<T>) => void
>m => m(42) : (m: (n: number) => void) => void
>m : (n: number) => void
>m(42) : void
>m : (n: number) => void
>42 : 42
// webidl-conversions example where substituion must occur, despite contravariance of the position
// due to the invariant usage in `Parameters`
type X<V> = V extends (...args: any[]) => any ? (...args: Parameters<V>) => void : Function;
>X : X<V>
>args : any[]
>args : Parameters<V>
// vscode - another `Parameters` example
export type AddFirstParameterToFunctions<Target> = {
>AddFirstParameterToFunctions : AddFirstParameterToFunctions<Target>
[K in keyof Target]: Target[K] extends (...args: any[]) => void
>args : any[]
? (...args: Parameters<Target[K]>) => void
>args : Parameters<Target[K]>
: void
};