|
1 | 1 | //// [indexAccessCombinedInference.ts]
|
| 2 | +// Simple case |
2 | 3 | interface Args {
|
3 | 4 | TA: object,
|
4 | 5 | TY: object
|
5 | 6 | }
|
6 | 7 |
|
7 |
| -function foo<T extends Args>( |
| 8 | +declare function foo<T extends Args>( |
8 | 9 | a: T["TA"],
|
9 |
| - b: T["TY"]): T["TA"] & T["TY"] { |
10 |
| - return undefined!; |
11 |
| -} |
| 10 | + b: T["TY"]): T["TA"] & T["TY"]; |
12 | 11 |
|
13 | 12 | const x = foo({
|
14 | 13 | x: {
|
15 | 14 | j: 12,
|
16 | 15 | i: 11
|
17 | 16 | }
|
18 |
| -}, { y: 42 }); |
| 17 | +}, { y: 42 }); |
| 18 | + |
| 19 | +// Union result type |
| 20 | +interface A { |
| 21 | + foo: number; |
| 22 | +} |
| 23 | +interface B { |
| 24 | + bar: string; |
| 25 | +} |
| 26 | +declare const something: A | B; |
| 27 | + |
| 28 | +const y = foo(something, { bat: 42 }); |
| 29 | + |
| 30 | +// Union key type |
| 31 | +interface Args2 { |
| 32 | + TA?: object, // Optional since only one of TA or TB needs to be infered in the below argument list |
| 33 | + TB?: object, |
| 34 | + TY: object |
| 35 | +} |
| 36 | +declare function foo2<T extends Args2>( |
| 37 | + a: T["TA"] | T["TB"], |
| 38 | + b: T["TY"]): {a: T["TA"], b: T["TB"]} & T["TY"]; |
| 39 | +declare function foo3<T extends Args2>( // Morally equivalent to foo2 |
| 40 | + a: T["TA" | "TB"], |
| 41 | + b: T["TY"]): {a: T["TA"], b: T["TB"]} & T["TY"]; |
| 42 | +let z = foo2({ |
| 43 | + x: { |
| 44 | + j: 12, |
| 45 | + i: 11 |
| 46 | + } |
| 47 | +}, { y: 42 }); |
| 48 | +let zz = foo3({ |
| 49 | + x: { |
| 50 | + j: 12, |
| 51 | + i: 11 |
| 52 | + } |
| 53 | +}, { y: 42 }); |
| 54 | +z = zz; |
| 55 | +zz = z; |
| 56 | + |
| 57 | +// Higher-order |
| 58 | +interface Args3 { |
| 59 | + Key: "A" | "B", |
| 60 | + A: object, |
| 61 | + B: object, |
| 62 | + Merge: object, |
| 63 | +} |
| 64 | +declare const either: "A" | "B"; |
| 65 | +declare function pickOne<T extends Args3>(key: T["Key"], left: T["A"], right: T["B"], into: T["Merge"]): T[T["Key"]] & T["Merge"]; |
| 66 | + |
| 67 | +const opt1 = pickOne("A", {x: 12}, {y: ""}, {z: /./}); |
| 68 | +const opt2 = pickOne("B", {x: 12}, {y: ""}, {z: /./}); |
| 69 | +const opt3 = pickOne(either, {x: 12}, {y: ""}, {z: /./}); |
| 70 | + |
| 71 | +const pickDelayed = <TKey extends Args3["Key"]>(x: TKey) => pickOne(x, {j: x}, {i: x}, {chosen: x}); |
| 72 | +const opt4 = pickDelayed("A"); |
| 73 | +const opt5 = pickDelayed("B"); |
| 74 | +const opt6 = pickDelayed(either); |
| 75 | + |
| 76 | +// Reopenable |
| 77 | +interface Args3 { |
| 78 | + /** |
| 79 | + * One must make patched parameters optional, otherwise signatures expecting the unpatched |
| 80 | + * interface (ie, pickOne above) will not be able to produce a type satisfying the interface |
| 81 | + * (as there are no inference sites for the new members) and will fall back to the constraints on each member |
| 82 | + */ |
| 83 | + Extra?: object, |
| 84 | +} |
| 85 | +declare function pickOne<T extends Args3>(key: T["Key"], left: T["A"], right: T["B"], into: T["Merge"], extra: T["Extra"]): T[T["Key"]] & {into: T["Merge"], extra: T["Extra"]}; |
| 86 | +const opt7 = pickOne("A", {x: 12}, {y: ""}, {z: /./}, {z: /./}); |
| 87 | +const opt8 = pickOne("B", {x: 12}, {y: ""}, {z: /./}, {z: /./}); |
| 88 | +const opt9 = pickOne(either, {x: 12}, {y: ""}, {z: /./}, {z: /./}); |
| 89 | + |
| 90 | +// Interactions with `this` types |
| 91 | +interface TPicker { |
| 92 | + Key: keyof this, |
| 93 | + X: number, |
| 94 | + Y: string |
| 95 | +} |
| 96 | +declare function chooseLiteral<T extends TPicker>(choice: T["Key"], x: T["X"], y:T["Y"]): T[T["Key"]]; |
| 97 | +const cx = chooseLiteral("X", 1, "no"); |
| 98 | +const cy = chooseLiteral("Y", 0, "yes"); |
| 99 | +const ceither = chooseLiteral("X" as "X" | "Y", 1, "yes"); |
| 100 | +const cneither = chooseLiteral("Key", 0, "no"); |
| 101 | + |
| 102 | +// Multiple inference sites |
| 103 | +interface Args4 { |
| 104 | + 0: object, |
| 105 | + 1: Record<keyof this["0"], Function>, |
| 106 | +} |
| 107 | +declare function dualInputs<T extends Args4>(x: T["0"], y: T["0"], toDelay: T["1"]): T["0"] & {transformers: T["1"]}; |
| 108 | + |
| 109 | +const result = dualInputs({x: 0}, {x: 1}, {x: () => ""}); |
| 110 | + |
19 | 111 |
|
20 | 112 | //// [indexAccessCombinedInference.js]
|
21 |
| -function foo(a, b) { |
22 |
| - return undefined; |
23 |
| -} |
24 | 113 | var x = foo({
|
25 | 114 | x: {
|
26 | 115 | j: 12,
|
27 | 116 | i: 11
|
28 | 117 | }
|
29 | 118 | }, { y: 42 });
|
| 119 | +var y = foo(something, { bat: 42 }); |
| 120 | +var z = foo2({ |
| 121 | + x: { |
| 122 | + j: 12, |
| 123 | + i: 11 |
| 124 | + } |
| 125 | +}, { y: 42 }); |
| 126 | +var zz = foo3({ |
| 127 | + x: { |
| 128 | + j: 12, |
| 129 | + i: 11 |
| 130 | + } |
| 131 | +}, { y: 42 }); |
| 132 | +z = zz; |
| 133 | +zz = z; |
| 134 | +var opt1 = pickOne("A", { x: 12 }, { y: "" }, { z: /./ }); |
| 135 | +var opt2 = pickOne("B", { x: 12 }, { y: "" }, { z: /./ }); |
| 136 | +var opt3 = pickOne(either, { x: 12 }, { y: "" }, { z: /./ }); |
| 137 | +var pickDelayed = function (x) { return pickOne(x, { j: x }, { i: x }, { chosen: x }); }; |
| 138 | +var opt4 = pickDelayed("A"); |
| 139 | +var opt5 = pickDelayed("B"); |
| 140 | +var opt6 = pickDelayed(either); |
| 141 | +var opt7 = pickOne("A", { x: 12 }, { y: "" }, { z: /./ }, { z: /./ }); |
| 142 | +var opt8 = pickOne("B", { x: 12 }, { y: "" }, { z: /./ }, { z: /./ }); |
| 143 | +var opt9 = pickOne(either, { x: 12 }, { y: "" }, { z: /./ }, { z: /./ }); |
| 144 | +var cx = chooseLiteral("X", 1, "no"); |
| 145 | +var cy = chooseLiteral("Y", 0, "yes"); |
| 146 | +var ceither = chooseLiteral("X", 1, "yes"); |
| 147 | +var cneither = chooseLiteral("Key", 0, "no"); |
| 148 | +var result = dualInputs({ x: 0 }, { x: 1 }, { x: function () { return ""; } }); |
0 commit comments