Skip to content

Commit 9b7f291

Browse files
authored
Improve contextual typing of ending tuple elements (#53036)
1 parent 905a0b4 commit 9b7f291

13 files changed

+625
-29
lines changed

src/compiler/checker.ts

+44-18
Original file line numberDiff line numberDiff line change
@@ -29090,18 +29090,45 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
2909029090
return undefined;
2909129091
}
2909229092

29093-
// In an array literal contextually typed by a type T, the contextual type of an element expression at index N is
29094-
// the type of the property with the numeric name N in T, if one exists. Otherwise, if T has a numeric index signature,
29095-
// it is the type of the numeric index signature in T. Otherwise, in ES6 and higher, the contextual type is the iterated
29096-
// type of T.
29097-
function getContextualTypeForElementExpression(arrayContextualType: Type | undefined, index: number): Type | undefined {
29098-
return arrayContextualType && (
29099-
index >= 0 && getTypeOfPropertyOfContextualType(arrayContextualType, "" + index as __String) ||
29100-
mapType(arrayContextualType, t =>
29101-
isTupleType(t) ?
29102-
getElementTypeOfSliceOfTupleType(t, 0, /*endSkipCount*/ 0, /*writing*/ false, /*noReductions*/ true) :
29103-
getIteratedTypeOrElementType(IterationUse.Element, t, undefinedType, /*errorNode*/ undefined, /*checkAssignability*/ false),
29104-
/*noReductions*/ true));
29093+
function getSpreadIndices(elements: readonly Node[]) {
29094+
let first, last;
29095+
for (let i = 0; i < elements.length; i++) {
29096+
if (isSpreadElement(elements[i])) {
29097+
first ??= i;
29098+
last = i;
29099+
}
29100+
}
29101+
return { first, last };
29102+
}
29103+
29104+
function getContextualTypeForElementExpression(type: Type | undefined, index: number, length?: number, firstSpreadIndex?: number, lastSpreadIndex?: number): Type | undefined {
29105+
return type && mapType(type, t => {
29106+
if (isTupleType(t)) {
29107+
// If index is before any spread element and within the fixed part of the contextual tuple type, return
29108+
// the type of the contextual tuple element.
29109+
if ((firstSpreadIndex === undefined || index < firstSpreadIndex) && index < t.target.fixedLength) {
29110+
return getTypeArguments(t)[index];
29111+
}
29112+
// When the length is known and the index is after all spread elements we compute the offset from the element
29113+
// to the end and the number of ending fixed elements in the contextual tuple type.
29114+
const offset = length !== undefined && (lastSpreadIndex === undefined || index > lastSpreadIndex) ? length - index : 0;
29115+
const fixedEndLength = offset > 0 && t.target.hasRestElement ? getEndElementCount(t.target, ElementFlags.Fixed) : 0;
29116+
// If the offset is within the ending fixed part of the contextual tuple type, return the type of the contextual
29117+
// tuple element.
29118+
if (offset > 0 && offset <= fixedEndLength) {
29119+
return getTypeArguments(t)[getTypeReferenceArity(t) - offset];
29120+
}
29121+
// Return a union of the possible contextual element types with no subtype reduction.
29122+
return getElementTypeOfSliceOfTupleType(t,
29123+
firstSpreadIndex === undefined ? t.target.fixedLength : Math.min(t.target.fixedLength, firstSpreadIndex),
29124+
length === undefined || lastSpreadIndex === undefined ? fixedEndLength : Math.min(fixedEndLength, length - lastSpreadIndex),
29125+
/*writing*/ false, /*noReductions*/ true);
29126+
}
29127+
// If element index is known and a contextual property with that name exists, return it. Otherwise return the
29128+
// iterated or element type of the contextual type.
29129+
return (!firstSpreadIndex || index < firstSpreadIndex) && getTypeOfPropertyOfContextualType(t, "" + index as __String) ||
29130+
getIteratedTypeOrElementType(IterationUse.Element, t, undefinedType, /*errorNode*/ undefined, /*checkAssignability*/ false);
29131+
}, /*noReductions*/ true);
2910529132
}
2910629133

2910729134
// In a contextually typed conditional expression, the true/false expressions are contextually typed by the same type.
@@ -29332,12 +29359,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
2933229359
case SyntaxKind.ArrayLiteralExpression: {
2933329360
const arrayLiteral = parent as ArrayLiteralExpression;
2933429361
const type = getApparentTypeOfContextualType(arrayLiteral, contextFlags);
29335-
// The index of an array literal element doesn't necessarily line up with the index of the corresponding
29336-
// element in a contextual tuple type when there are preceding spread elements in the array literal. For
29337-
// this reason we only pass indices for elements that precede the first spread element.
29338-
const spreadIndex = getNodeLinks(arrayLiteral).firstSpreadIndex ??= findIndex(arrayLiteral.elements, isSpreadElement);
2933929362
const elementIndex = indexOfNode(arrayLiteral.elements, node);
29340-
return getContextualTypeForElementExpression(type, spreadIndex < 0 || elementIndex < spreadIndex ? elementIndex : -1);
29363+
const spreadIndices = getNodeLinks(arrayLiteral).spreadIndices ??= getSpreadIndices(arrayLiteral.elements);
29364+
return getContextualTypeForElementExpression(type, elementIndex, arrayLiteral.elements.length, spreadIndices.first, spreadIndices.last);
2934129365
}
2934229366
case SyntaxKind.ConditionalExpression:
2934329367
return getContextualTypeForConditionalOperand(node, contextFlags);
@@ -32332,7 +32356,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
3233232356
}
3233332357
}
3233432358
else {
32335-
const contextualType = getIndexedAccessType(restType, getNumberLiteralType(i - index), AccessFlags.Contextual);
32359+
const contextualType = isTupleType(restType) ?
32360+
getContextualTypeForElementExpression(restType, i - index, argCount - index) || unknownType :
32361+
getIndexedAccessType(restType, getNumberLiteralType(i - index), AccessFlags.Contextual);
3233632362
const argType = checkExpressionWithContextualType(arg, contextualType, context, checkMode);
3233732363
const hasPrimitiveContextualType = inConstContext || maybeTypeOfKind(contextualType, TypeFlags.Primitive | TypeFlags.Index | TypeFlags.TemplateLiteral | TypeFlags.StringMapping);
3233832364
types.push(hasPrimitiveContextualType ? getRegularTypeOfLiteralType(argType) : getWidenedLiteralType(argType));

src/compiler/types.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -6028,7 +6028,7 @@ export interface NodeLinks {
60286028
declarationRequiresScopeChange?: boolean; // Set by `useOuterVariableScopeInParameter` in checker when downlevel emit would change the name resolution scope inside of a parameter.
60296029
serializedTypes?: Map<string, SerializedTypeEntry>; // Collection of types serialized at this location
60306030
decoratorSignature?: Signature; // Signature for decorator as if invoked by the runtime.
6031-
firstSpreadIndex?: number; // Index of first spread element in array literal (-1 for none)
6031+
spreadIndices?: { first: number | undefined, last: number | undefined }; // Indices of first and last spread elements in array literal
60326032
parameterInitializerContainsUndefined?: boolean; // True if this is a parameter declaration whose type annotation contains "undefined".
60336033
fakeScopeForSignatureDeclaration?: boolean; // True if this is a fake scope injected into an enclosing declaration chain.
60346034
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
tests/cases/compiler/contextualSignatureInArrayElementPrefersArrayUnionMemberLibEs2015.ts(8,4): error TS7006: Parameter 'arg' implicitly has an 'any' type.
2+
3+
4+
==== tests/cases/compiler/contextualSignatureInArrayElementPrefersArrayUnionMemberLibEs2015.ts (1 errors) ====
5+
// repro from #52588
6+
7+
declare function test(
8+
arg: Record<string, (arg: string) => void> | Array<(arg: number) => void>
9+
): void;
10+
11+
test([
12+
(arg) => {
13+
~~~
14+
!!! error TS7006: Parameter 'arg' implicitly has an 'any' type.
15+
arg; // number
16+
},
17+
]);
18+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
tests/cases/compiler/contextualSignatureInArrayElementPrefersArrayUnionMemberLibEs5.ts(8,4): error TS7006: Parameter 'arg' implicitly has an 'any' type.
2+
3+
4+
==== tests/cases/compiler/contextualSignatureInArrayElementPrefersArrayUnionMemberLibEs5.ts (1 errors) ====
5+
// repro from #52588
6+
7+
declare function test(
8+
arg: Record<string, (arg: string) => void> | Array<(arg: number) => void>
9+
): void;
10+
11+
test([
12+
(arg) => {
13+
~~~
14+
!!! error TS7006: Parameter 'arg' implicitly has an 'any' type.
15+
arg; // number
16+
},
17+
]);
18+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
tests/cases/conformance/types/tuple/contextualTypeTupleEnd.ts(8,1): error TS2345: Argument of type '[]' is not assignable to parameter of type '[...((arg: number) => void)[], (arg: string) => void]'.
2+
Source has 0 element(s) but target requires 1.
3+
tests/cases/conformance/types/tuple/contextualTypeTupleEnd.ts(13,7): error TS2322: Type '[]' is not assignable to type 'Funcs'.
4+
Source has 0 element(s) but target requires 1.
5+
tests/cases/conformance/types/tuple/contextualTypeTupleEnd.ts(43,12): error TS2339: Property 'foo' does not exist on type 'number'.
6+
tests/cases/conformance/types/tuple/contextualTypeTupleEnd.ts(44,12): error TS2339: Property 'bar' does not exist on type 'number'.
7+
8+
9+
==== tests/cases/conformance/types/tuple/contextualTypeTupleEnd.ts (4 errors) ====
10+
type Funcs = [...((arg: number) => void)[], (arg: string) => void];
11+
12+
declare function num(x: number): void;
13+
declare function str(x: string): void;
14+
15+
declare function f1(...args: Funcs): void;
16+
17+
f1(); // Error
18+
~~~~
19+
!!! error TS2345: Argument of type '[]' is not assignable to parameter of type '[...((arg: number) => void)[], (arg: string) => void]'.
20+
!!! error TS2345: Source has 0 element(s) but target requires 1.
21+
f1(x => str(x));
22+
f1(x => num(x), x => str(x));
23+
f1(x => num(x), x => num(x), x => str(x));
24+
25+
const a0: Funcs = []; // Error
26+
~~
27+
!!! error TS2322: Type '[]' is not assignable to type 'Funcs'.
28+
!!! error TS2322: Source has 0 element(s) but target requires 1.
29+
const a1: Funcs = [x => str(x)];
30+
const a2: Funcs = [x => num(x), x => str(x)];
31+
const a3: Funcs = [x => num(x), x => num(x), x => str(x)];
32+
33+
// Repro from #43122
34+
35+
export type Selector<State> = (state: State) => unknown;
36+
export type SelectorTuple<State> = Selector<State>[];
37+
38+
export type ExampleState = {
39+
foo: "foo";
40+
bar: 42;
41+
};
42+
43+
export function createSelector<S extends SelectorTuple<ExampleState>>(...selectors: [...selectors: S, f: (x: any) => any]) {
44+
console.log(selectors);
45+
}
46+
47+
createSelector(
48+
x => x.foo,
49+
x => x.bar,
50+
() => 42
51+
);
52+
53+
// Repro from #43122
54+
55+
declare function example(...args: [...((n: number) => void)[], (x: any) => void]): void
56+
57+
example(
58+
x => x.foo, // Error
59+
~~~
60+
!!! error TS2339: Property 'foo' does not exist on type 'number'.
61+
x => x.bar, // Error
62+
~~~
63+
!!! error TS2339: Property 'bar' does not exist on type 'number'.
64+
x => x.baz,
65+
);
66+
67+
// Repro from #52846
68+
69+
declare function test(...args: [...((arg: number) => void)[], (arg: string) => void]): void;
70+
71+
test(a => a, b => b, c => c);
72+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
1+
=== tests/cases/conformance/types/tuple/contextualTypeTupleEnd.ts ===
2+
type Funcs = [...((arg: number) => void)[], (arg: string) => void];
3+
>Funcs : Symbol(Funcs, Decl(contextualTypeTupleEnd.ts, 0, 0))
4+
>arg : Symbol(arg, Decl(contextualTypeTupleEnd.ts, 0, 19))
5+
>arg : Symbol(arg, Decl(contextualTypeTupleEnd.ts, 0, 45))
6+
7+
declare function num(x: number): void;
8+
>num : Symbol(num, Decl(contextualTypeTupleEnd.ts, 0, 67))
9+
>x : Symbol(x, Decl(contextualTypeTupleEnd.ts, 2, 21))
10+
11+
declare function str(x: string): void;
12+
>str : Symbol(str, Decl(contextualTypeTupleEnd.ts, 2, 38))
13+
>x : Symbol(x, Decl(contextualTypeTupleEnd.ts, 3, 21))
14+
15+
declare function f1(...args: Funcs): void;
16+
>f1 : Symbol(f1, Decl(contextualTypeTupleEnd.ts, 3, 38))
17+
>args : Symbol(args, Decl(contextualTypeTupleEnd.ts, 5, 20))
18+
>Funcs : Symbol(Funcs, Decl(contextualTypeTupleEnd.ts, 0, 0))
19+
20+
f1(); // Error
21+
>f1 : Symbol(f1, Decl(contextualTypeTupleEnd.ts, 3, 38))
22+
23+
f1(x => str(x));
24+
>f1 : Symbol(f1, Decl(contextualTypeTupleEnd.ts, 3, 38))
25+
>x : Symbol(x, Decl(contextualTypeTupleEnd.ts, 8, 3))
26+
>str : Symbol(str, Decl(contextualTypeTupleEnd.ts, 2, 38))
27+
>x : Symbol(x, Decl(contextualTypeTupleEnd.ts, 8, 3))
28+
29+
f1(x => num(x), x => str(x));
30+
>f1 : Symbol(f1, Decl(contextualTypeTupleEnd.ts, 3, 38))
31+
>x : Symbol(x, Decl(contextualTypeTupleEnd.ts, 9, 3))
32+
>num : Symbol(num, Decl(contextualTypeTupleEnd.ts, 0, 67))
33+
>x : Symbol(x, Decl(contextualTypeTupleEnd.ts, 9, 3))
34+
>x : Symbol(x, Decl(contextualTypeTupleEnd.ts, 9, 15))
35+
>str : Symbol(str, Decl(contextualTypeTupleEnd.ts, 2, 38))
36+
>x : Symbol(x, Decl(contextualTypeTupleEnd.ts, 9, 15))
37+
38+
f1(x => num(x), x => num(x), x => str(x));
39+
>f1 : Symbol(f1, Decl(contextualTypeTupleEnd.ts, 3, 38))
40+
>x : Symbol(x, Decl(contextualTypeTupleEnd.ts, 10, 3))
41+
>num : Symbol(num, Decl(contextualTypeTupleEnd.ts, 0, 67))
42+
>x : Symbol(x, Decl(contextualTypeTupleEnd.ts, 10, 3))
43+
>x : Symbol(x, Decl(contextualTypeTupleEnd.ts, 10, 15))
44+
>num : Symbol(num, Decl(contextualTypeTupleEnd.ts, 0, 67))
45+
>x : Symbol(x, Decl(contextualTypeTupleEnd.ts, 10, 15))
46+
>x : Symbol(x, Decl(contextualTypeTupleEnd.ts, 10, 28))
47+
>str : Symbol(str, Decl(contextualTypeTupleEnd.ts, 2, 38))
48+
>x : Symbol(x, Decl(contextualTypeTupleEnd.ts, 10, 28))
49+
50+
const a0: Funcs = []; // Error
51+
>a0 : Symbol(a0, Decl(contextualTypeTupleEnd.ts, 12, 5))
52+
>Funcs : Symbol(Funcs, Decl(contextualTypeTupleEnd.ts, 0, 0))
53+
54+
const a1: Funcs = [x => str(x)];
55+
>a1 : Symbol(a1, Decl(contextualTypeTupleEnd.ts, 13, 5))
56+
>Funcs : Symbol(Funcs, Decl(contextualTypeTupleEnd.ts, 0, 0))
57+
>x : Symbol(x, Decl(contextualTypeTupleEnd.ts, 13, 19))
58+
>str : Symbol(str, Decl(contextualTypeTupleEnd.ts, 2, 38))
59+
>x : Symbol(x, Decl(contextualTypeTupleEnd.ts, 13, 19))
60+
61+
const a2: Funcs = [x => num(x), x => str(x)];
62+
>a2 : Symbol(a2, Decl(contextualTypeTupleEnd.ts, 14, 5))
63+
>Funcs : Symbol(Funcs, Decl(contextualTypeTupleEnd.ts, 0, 0))
64+
>x : Symbol(x, Decl(contextualTypeTupleEnd.ts, 14, 19))
65+
>num : Symbol(num, Decl(contextualTypeTupleEnd.ts, 0, 67))
66+
>x : Symbol(x, Decl(contextualTypeTupleEnd.ts, 14, 19))
67+
>x : Symbol(x, Decl(contextualTypeTupleEnd.ts, 14, 31))
68+
>str : Symbol(str, Decl(contextualTypeTupleEnd.ts, 2, 38))
69+
>x : Symbol(x, Decl(contextualTypeTupleEnd.ts, 14, 31))
70+
71+
const a3: Funcs = [x => num(x), x => num(x), x => str(x)];
72+
>a3 : Symbol(a3, Decl(contextualTypeTupleEnd.ts, 15, 5))
73+
>Funcs : Symbol(Funcs, Decl(contextualTypeTupleEnd.ts, 0, 0))
74+
>x : Symbol(x, Decl(contextualTypeTupleEnd.ts, 15, 19))
75+
>num : Symbol(num, Decl(contextualTypeTupleEnd.ts, 0, 67))
76+
>x : Symbol(x, Decl(contextualTypeTupleEnd.ts, 15, 19))
77+
>x : Symbol(x, Decl(contextualTypeTupleEnd.ts, 15, 31))
78+
>num : Symbol(num, Decl(contextualTypeTupleEnd.ts, 0, 67))
79+
>x : Symbol(x, Decl(contextualTypeTupleEnd.ts, 15, 31))
80+
>x : Symbol(x, Decl(contextualTypeTupleEnd.ts, 15, 44))
81+
>str : Symbol(str, Decl(contextualTypeTupleEnd.ts, 2, 38))
82+
>x : Symbol(x, Decl(contextualTypeTupleEnd.ts, 15, 44))
83+
84+
// Repro from #43122
85+
86+
export type Selector<State> = (state: State) => unknown;
87+
>Selector : Symbol(Selector, Decl(contextualTypeTupleEnd.ts, 15, 58))
88+
>State : Symbol(State, Decl(contextualTypeTupleEnd.ts, 19, 21))
89+
>state : Symbol(state, Decl(contextualTypeTupleEnd.ts, 19, 31))
90+
>State : Symbol(State, Decl(contextualTypeTupleEnd.ts, 19, 21))
91+
92+
export type SelectorTuple<State> = Selector<State>[];
93+
>SelectorTuple : Symbol(SelectorTuple, Decl(contextualTypeTupleEnd.ts, 19, 56))
94+
>State : Symbol(State, Decl(contextualTypeTupleEnd.ts, 20, 26))
95+
>Selector : Symbol(Selector, Decl(contextualTypeTupleEnd.ts, 15, 58))
96+
>State : Symbol(State, Decl(contextualTypeTupleEnd.ts, 20, 26))
97+
98+
export type ExampleState = {
99+
>ExampleState : Symbol(ExampleState, Decl(contextualTypeTupleEnd.ts, 20, 53))
100+
101+
foo: "foo";
102+
>foo : Symbol(foo, Decl(contextualTypeTupleEnd.ts, 22, 28))
103+
104+
bar: 42;
105+
>bar : Symbol(bar, Decl(contextualTypeTupleEnd.ts, 23, 15))
106+
107+
};
108+
109+
export function createSelector<S extends SelectorTuple<ExampleState>>(...selectors: [...selectors: S, f: (x: any) => any]) {
110+
>createSelector : Symbol(createSelector, Decl(contextualTypeTupleEnd.ts, 25, 2))
111+
>S : Symbol(S, Decl(contextualTypeTupleEnd.ts, 27, 31))
112+
>SelectorTuple : Symbol(SelectorTuple, Decl(contextualTypeTupleEnd.ts, 19, 56))
113+
>ExampleState : Symbol(ExampleState, Decl(contextualTypeTupleEnd.ts, 20, 53))
114+
>selectors : Symbol(selectors, Decl(contextualTypeTupleEnd.ts, 27, 70))
115+
>S : Symbol(S, Decl(contextualTypeTupleEnd.ts, 27, 31))
116+
>x : Symbol(x, Decl(contextualTypeTupleEnd.ts, 27, 106))
117+
118+
console.log(selectors);
119+
>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
120+
>console : Symbol(console, Decl(lib.dom.d.ts, --, --))
121+
>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
122+
>selectors : Symbol(selectors, Decl(contextualTypeTupleEnd.ts, 27, 70))
123+
}
124+
125+
createSelector(
126+
>createSelector : Symbol(createSelector, Decl(contextualTypeTupleEnd.ts, 25, 2))
127+
128+
x => x.foo,
129+
>x : Symbol(x, Decl(contextualTypeTupleEnd.ts, 31, 15))
130+
>x.foo : Symbol(foo, Decl(contextualTypeTupleEnd.ts, 22, 28))
131+
>x : Symbol(x, Decl(contextualTypeTupleEnd.ts, 31, 15))
132+
>foo : Symbol(foo, Decl(contextualTypeTupleEnd.ts, 22, 28))
133+
134+
x => x.bar,
135+
>x : Symbol(x, Decl(contextualTypeTupleEnd.ts, 32, 15))
136+
>x.bar : Symbol(bar, Decl(contextualTypeTupleEnd.ts, 23, 15))
137+
>x : Symbol(x, Decl(contextualTypeTupleEnd.ts, 32, 15))
138+
>bar : Symbol(bar, Decl(contextualTypeTupleEnd.ts, 23, 15))
139+
140+
() => 42
141+
);
142+
143+
// Repro from #43122
144+
145+
declare function example(...args: [...((n: number) => void)[], (x: any) => void]): void
146+
>example : Symbol(example, Decl(contextualTypeTupleEnd.ts, 35, 2))
147+
>args : Symbol(args, Decl(contextualTypeTupleEnd.ts, 39, 25))
148+
>n : Symbol(n, Decl(contextualTypeTupleEnd.ts, 39, 40))
149+
>x : Symbol(x, Decl(contextualTypeTupleEnd.ts, 39, 64))
150+
151+
example(
152+
>example : Symbol(example, Decl(contextualTypeTupleEnd.ts, 35, 2))
153+
154+
x => x.foo, // Error
155+
>x : Symbol(x, Decl(contextualTypeTupleEnd.ts, 41, 8))
156+
>x : Symbol(x, Decl(contextualTypeTupleEnd.ts, 41, 8))
157+
158+
x => x.bar, // Error
159+
>x : Symbol(x, Decl(contextualTypeTupleEnd.ts, 42, 15))
160+
>x : Symbol(x, Decl(contextualTypeTupleEnd.ts, 42, 15))
161+
162+
x => x.baz,
163+
>x : Symbol(x, Decl(contextualTypeTupleEnd.ts, 43, 15))
164+
>x : Symbol(x, Decl(contextualTypeTupleEnd.ts, 43, 15))
165+
166+
);
167+
168+
// Repro from #52846
169+
170+
declare function test(...args: [...((arg: number) => void)[], (arg: string) => void]): void;
171+
>test : Symbol(test, Decl(contextualTypeTupleEnd.ts, 45, 2))
172+
>args : Symbol(args, Decl(contextualTypeTupleEnd.ts, 49, 22))
173+
>arg : Symbol(arg, Decl(contextualTypeTupleEnd.ts, 49, 37))
174+
>arg : Symbol(arg, Decl(contextualTypeTupleEnd.ts, 49, 63))
175+
176+
test(a => a, b => b, c => c);
177+
>test : Symbol(test, Decl(contextualTypeTupleEnd.ts, 45, 2))
178+
>a : Symbol(a, Decl(contextualTypeTupleEnd.ts, 51, 5))
179+
>a : Symbol(a, Decl(contextualTypeTupleEnd.ts, 51, 5))
180+
>b : Symbol(b, Decl(contextualTypeTupleEnd.ts, 51, 12))
181+
>b : Symbol(b, Decl(contextualTypeTupleEnd.ts, 51, 12))
182+
>c : Symbol(c, Decl(contextualTypeTupleEnd.ts, 51, 20))
183+
>c : Symbol(c, Decl(contextualTypeTupleEnd.ts, 51, 20))
184+

0 commit comments

Comments
 (0)