diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 16e982bfff38b..935e2df178b75 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -29079,18 +29079,45 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return undefined; } - // In an array literal contextually typed by a type T, the contextual type of an element expression at index N is - // the type of the property with the numeric name N in T, if one exists. Otherwise, if T has a numeric index signature, - // it is the type of the numeric index signature in T. Otherwise, in ES6 and higher, the contextual type is the iterated - // type of T. - function getContextualTypeForElementExpression(arrayContextualType: Type | undefined, index: number): Type | undefined { - return arrayContextualType && ( - index >= 0 && getTypeOfPropertyOfContextualType(arrayContextualType, "" + index as __String) || - mapType(arrayContextualType, t => - isTupleType(t) ? - getElementTypeOfSliceOfTupleType(t, 0, /*endSkipCount*/ 0, /*writing*/ false, /*noReductions*/ true) : - getIteratedTypeOrElementType(IterationUse.Element, t, undefinedType, /*errorNode*/ undefined, /*checkAssignability*/ false), - /*noReductions*/ true)); + function getSpreadIndices(elements: readonly Node[]) { + let first, last; + for (let i = 0; i < elements.length; i++) { + if (isSpreadElement(elements[i])) { + first ??= i; + last = i; + } + } + return { first, last }; + } + + function getContextualTypeForElementExpression(type: Type | undefined, index: number, length?: number, firstSpreadIndex?: number, lastSpreadIndex?: number): Type | undefined { + return type && mapType(type, t => { + if (isTupleType(t)) { + // If index is before any spread element and within the fixed part of the contextual tuple type, return + // the type of the contextual tuple element. + if ((firstSpreadIndex === undefined || index < firstSpreadIndex) && index < t.target.fixedLength) { + return getTypeArguments(t)[index]; + } + // When the length is known and the index is after all spread elements we compute the offset from the element + // to the end and the number of ending fixed elements in the contextual tuple type. + const offset = length !== undefined && (lastSpreadIndex === undefined || index > lastSpreadIndex) ? length - index : 0; + const fixedEndLength = offset > 0 && t.target.hasRestElement ? getEndElementCount(t.target, ElementFlags.Fixed) : 0; + // If the offset is within the ending fixed part of the contextual tuple type, return the type of the contextual + // tuple element. + if (offset > 0 && offset <= fixedEndLength) { + return getTypeArguments(t)[getTypeReferenceArity(t) - offset]; + } + // Return a union of the possible contextual element types with no subtype reduction. + return getElementTypeOfSliceOfTupleType(t, + firstSpreadIndex === undefined ? t.target.fixedLength : Math.min(t.target.fixedLength, firstSpreadIndex), + length === undefined || lastSpreadIndex === undefined ? fixedEndLength : Math.min(fixedEndLength, length - lastSpreadIndex), + /*writing*/ false, /*noReductions*/ true); + } + // If element index is known and a contextual property with that name exists, return it. Otherwise return the + // iterated or element type of the contextual type. + return (!firstSpreadIndex || index < firstSpreadIndex) && getTypeOfPropertyOfContextualType(t, "" + index as __String) || + getIteratedTypeOrElementType(IterationUse.Element, t, undefinedType, /*errorNode*/ undefined, /*checkAssignability*/ false); + }, /*noReductions*/ true); } // In a contextually typed conditional expression, the true/false expressions are contextually typed by the same type. @@ -29321,12 +29348,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { case SyntaxKind.ArrayLiteralExpression: { const arrayLiteral = parent as ArrayLiteralExpression; const type = getApparentTypeOfContextualType(arrayLiteral, contextFlags); - // The index of an array literal element doesn't necessarily line up with the index of the corresponding - // element in a contextual tuple type when there are preceding spread elements in the array literal. For - // this reason we only pass indices for elements that precede the first spread element. - const spreadIndex = getNodeLinks(arrayLiteral).firstSpreadIndex ??= findIndex(arrayLiteral.elements, isSpreadElement); const elementIndex = indexOfNode(arrayLiteral.elements, node); - return getContextualTypeForElementExpression(type, spreadIndex < 0 || elementIndex < spreadIndex ? elementIndex : -1); + const spreadIndices = getNodeLinks(arrayLiteral).spreadIndices ??= getSpreadIndices(arrayLiteral.elements); + return getContextualTypeForElementExpression(type, elementIndex, arrayLiteral.elements.length, spreadIndices.first, spreadIndices.last); } case SyntaxKind.ConditionalExpression: return getContextualTypeForConditionalOperand(node, contextFlags); @@ -32321,7 +32345,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } else { - const contextualType = getIndexedAccessType(restType, getNumberLiteralType(i - index), AccessFlags.Contextual); + const contextualType = isTupleType(restType) ? + getContextualTypeForElementExpression(restType, i - index, argCount - index) || unknownType : + getIndexedAccessType(restType, getNumberLiteralType(i - index), AccessFlags.Contextual); const argType = checkExpressionWithContextualType(arg, contextualType, context, checkMode); const hasPrimitiveContextualType = inConstContext || maybeTypeOfKind(contextualType, TypeFlags.Primitive | TypeFlags.Index | TypeFlags.TemplateLiteral | TypeFlags.StringMapping); types.push(hasPrimitiveContextualType ? getRegularTypeOfLiteralType(argType) : getWidenedLiteralType(argType)); diff --git a/src/compiler/types.ts b/src/compiler/types.ts index b84d13a064299..3a2b6b04b1e8d 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -6028,7 +6028,7 @@ export interface NodeLinks { declarationRequiresScopeChange?: boolean; // Set by `useOuterVariableScopeInParameter` in checker when downlevel emit would change the name resolution scope inside of a parameter. serializedTypes?: Map; // Collection of types serialized at this location decoratorSignature?: Signature; // Signature for decorator as if invoked by the runtime. - firstSpreadIndex?: number; // Index of first spread element in array literal (-1 for none) + spreadIndices?: { first: number | undefined, last: number | undefined }; // Indices of first and last spread elements in array literal parameterInitializerContainsUndefined?: boolean; // True if this is a parameter declaration whose type annotation contains "undefined". fakeScopeForSignatureDeclaration?: boolean; // True if this is a fake scope injected into an enclosing declaration chain. } diff --git a/tests/baselines/reference/contextualSignatureInArrayElementPrefersArrayUnionMemberLibEs2015.errors.txt b/tests/baselines/reference/contextualSignatureInArrayElementPrefersArrayUnionMemberLibEs2015.errors.txt new file mode 100644 index 0000000000000..d6ee14f7b0f6c --- /dev/null +++ b/tests/baselines/reference/contextualSignatureInArrayElementPrefersArrayUnionMemberLibEs2015.errors.txt @@ -0,0 +1,18 @@ +tests/cases/compiler/contextualSignatureInArrayElementPrefersArrayUnionMemberLibEs2015.ts(8,4): error TS7006: Parameter 'arg' implicitly has an 'any' type. + + +==== tests/cases/compiler/contextualSignatureInArrayElementPrefersArrayUnionMemberLibEs2015.ts (1 errors) ==== + // repro from #52588 + + declare function test( + arg: Record void> | Array<(arg: number) => void> + ): void; + + test([ + (arg) => { + ~~~ +!!! error TS7006: Parameter 'arg' implicitly has an 'any' type. + arg; // number + }, + ]); + \ No newline at end of file diff --git a/tests/baselines/reference/contextualSignatureInArrayElementPrefersArrayUnionMemberLibEs5.errors.txt b/tests/baselines/reference/contextualSignatureInArrayElementPrefersArrayUnionMemberLibEs5.errors.txt new file mode 100644 index 0000000000000..76f299a99fb83 --- /dev/null +++ b/tests/baselines/reference/contextualSignatureInArrayElementPrefersArrayUnionMemberLibEs5.errors.txt @@ -0,0 +1,18 @@ +tests/cases/compiler/contextualSignatureInArrayElementPrefersArrayUnionMemberLibEs5.ts(8,4): error TS7006: Parameter 'arg' implicitly has an 'any' type. + + +==== tests/cases/compiler/contextualSignatureInArrayElementPrefersArrayUnionMemberLibEs5.ts (1 errors) ==== + // repro from #52588 + + declare function test( + arg: Record void> | Array<(arg: number) => void> + ): void; + + test([ + (arg) => { + ~~~ +!!! error TS7006: Parameter 'arg' implicitly has an 'any' type. + arg; // number + }, + ]); + \ No newline at end of file diff --git a/tests/baselines/reference/contextualTypeTupleEnd.errors.txt b/tests/baselines/reference/contextualTypeTupleEnd.errors.txt new file mode 100644 index 0000000000000..1a2af2096d6c2 --- /dev/null +++ b/tests/baselines/reference/contextualTypeTupleEnd.errors.txt @@ -0,0 +1,72 @@ +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]'. + Source has 0 element(s) but target requires 1. +tests/cases/conformance/types/tuple/contextualTypeTupleEnd.ts(13,7): error TS2322: Type '[]' is not assignable to type 'Funcs'. + Source has 0 element(s) but target requires 1. +tests/cases/conformance/types/tuple/contextualTypeTupleEnd.ts(43,12): error TS2339: Property 'foo' does not exist on type 'number'. +tests/cases/conformance/types/tuple/contextualTypeTupleEnd.ts(44,12): error TS2339: Property 'bar' does not exist on type 'number'. + + +==== tests/cases/conformance/types/tuple/contextualTypeTupleEnd.ts (4 errors) ==== + type Funcs = [...((arg: number) => void)[], (arg: string) => void]; + + declare function num(x: number): void; + declare function str(x: string): void; + + declare function f1(...args: Funcs): void; + + f1(); // Error + ~~~~ +!!! error TS2345: Argument of type '[]' is not assignable to parameter of type '[...((arg: number) => void)[], (arg: string) => void]'. +!!! error TS2345: Source has 0 element(s) but target requires 1. + f1(x => str(x)); + f1(x => num(x), x => str(x)); + f1(x => num(x), x => num(x), x => str(x)); + + const a0: Funcs = []; // Error + ~~ +!!! error TS2322: Type '[]' is not assignable to type 'Funcs'. +!!! error TS2322: Source has 0 element(s) but target requires 1. + const a1: Funcs = [x => str(x)]; + const a2: Funcs = [x => num(x), x => str(x)]; + const a3: Funcs = [x => num(x), x => num(x), x => str(x)]; + + // Repro from #43122 + + export type Selector = (state: State) => unknown; + export type SelectorTuple = Selector[]; + + export type ExampleState = { + foo: "foo"; + bar: 42; + }; + + export function createSelector>(...selectors: [...selectors: S, f: (x: any) => any]) { + console.log(selectors); + } + + createSelector( + x => x.foo, + x => x.bar, + () => 42 + ); + + // Repro from #43122 + + declare function example(...args: [...((n: number) => void)[], (x: any) => void]): void + + example( + x => x.foo, // Error + ~~~ +!!! error TS2339: Property 'foo' does not exist on type 'number'. + x => x.bar, // Error + ~~~ +!!! error TS2339: Property 'bar' does not exist on type 'number'. + x => x.baz, + ); + + // Repro from #52846 + + declare function test(...args: [...((arg: number) => void)[], (arg: string) => void]): void; + + test(a => a, b => b, c => c); + \ No newline at end of file diff --git a/tests/baselines/reference/contextualTypeTupleEnd.symbols b/tests/baselines/reference/contextualTypeTupleEnd.symbols new file mode 100644 index 0000000000000..5a09fc4227430 --- /dev/null +++ b/tests/baselines/reference/contextualTypeTupleEnd.symbols @@ -0,0 +1,184 @@ +=== tests/cases/conformance/types/tuple/contextualTypeTupleEnd.ts === +type Funcs = [...((arg: number) => void)[], (arg: string) => void]; +>Funcs : Symbol(Funcs, Decl(contextualTypeTupleEnd.ts, 0, 0)) +>arg : Symbol(arg, Decl(contextualTypeTupleEnd.ts, 0, 19)) +>arg : Symbol(arg, Decl(contextualTypeTupleEnd.ts, 0, 45)) + +declare function num(x: number): void; +>num : Symbol(num, Decl(contextualTypeTupleEnd.ts, 0, 67)) +>x : Symbol(x, Decl(contextualTypeTupleEnd.ts, 2, 21)) + +declare function str(x: string): void; +>str : Symbol(str, Decl(contextualTypeTupleEnd.ts, 2, 38)) +>x : Symbol(x, Decl(contextualTypeTupleEnd.ts, 3, 21)) + +declare function f1(...args: Funcs): void; +>f1 : Symbol(f1, Decl(contextualTypeTupleEnd.ts, 3, 38)) +>args : Symbol(args, Decl(contextualTypeTupleEnd.ts, 5, 20)) +>Funcs : Symbol(Funcs, Decl(contextualTypeTupleEnd.ts, 0, 0)) + +f1(); // Error +>f1 : Symbol(f1, Decl(contextualTypeTupleEnd.ts, 3, 38)) + +f1(x => str(x)); +>f1 : Symbol(f1, Decl(contextualTypeTupleEnd.ts, 3, 38)) +>x : Symbol(x, Decl(contextualTypeTupleEnd.ts, 8, 3)) +>str : Symbol(str, Decl(contextualTypeTupleEnd.ts, 2, 38)) +>x : Symbol(x, Decl(contextualTypeTupleEnd.ts, 8, 3)) + +f1(x => num(x), x => str(x)); +>f1 : Symbol(f1, Decl(contextualTypeTupleEnd.ts, 3, 38)) +>x : Symbol(x, Decl(contextualTypeTupleEnd.ts, 9, 3)) +>num : Symbol(num, Decl(contextualTypeTupleEnd.ts, 0, 67)) +>x : Symbol(x, Decl(contextualTypeTupleEnd.ts, 9, 3)) +>x : Symbol(x, Decl(contextualTypeTupleEnd.ts, 9, 15)) +>str : Symbol(str, Decl(contextualTypeTupleEnd.ts, 2, 38)) +>x : Symbol(x, Decl(contextualTypeTupleEnd.ts, 9, 15)) + +f1(x => num(x), x => num(x), x => str(x)); +>f1 : Symbol(f1, Decl(contextualTypeTupleEnd.ts, 3, 38)) +>x : Symbol(x, Decl(contextualTypeTupleEnd.ts, 10, 3)) +>num : Symbol(num, Decl(contextualTypeTupleEnd.ts, 0, 67)) +>x : Symbol(x, Decl(contextualTypeTupleEnd.ts, 10, 3)) +>x : Symbol(x, Decl(contextualTypeTupleEnd.ts, 10, 15)) +>num : Symbol(num, Decl(contextualTypeTupleEnd.ts, 0, 67)) +>x : Symbol(x, Decl(contextualTypeTupleEnd.ts, 10, 15)) +>x : Symbol(x, Decl(contextualTypeTupleEnd.ts, 10, 28)) +>str : Symbol(str, Decl(contextualTypeTupleEnd.ts, 2, 38)) +>x : Symbol(x, Decl(contextualTypeTupleEnd.ts, 10, 28)) + +const a0: Funcs = []; // Error +>a0 : Symbol(a0, Decl(contextualTypeTupleEnd.ts, 12, 5)) +>Funcs : Symbol(Funcs, Decl(contextualTypeTupleEnd.ts, 0, 0)) + +const a1: Funcs = [x => str(x)]; +>a1 : Symbol(a1, Decl(contextualTypeTupleEnd.ts, 13, 5)) +>Funcs : Symbol(Funcs, Decl(contextualTypeTupleEnd.ts, 0, 0)) +>x : Symbol(x, Decl(contextualTypeTupleEnd.ts, 13, 19)) +>str : Symbol(str, Decl(contextualTypeTupleEnd.ts, 2, 38)) +>x : Symbol(x, Decl(contextualTypeTupleEnd.ts, 13, 19)) + +const a2: Funcs = [x => num(x), x => str(x)]; +>a2 : Symbol(a2, Decl(contextualTypeTupleEnd.ts, 14, 5)) +>Funcs : Symbol(Funcs, Decl(contextualTypeTupleEnd.ts, 0, 0)) +>x : Symbol(x, Decl(contextualTypeTupleEnd.ts, 14, 19)) +>num : Symbol(num, Decl(contextualTypeTupleEnd.ts, 0, 67)) +>x : Symbol(x, Decl(contextualTypeTupleEnd.ts, 14, 19)) +>x : Symbol(x, Decl(contextualTypeTupleEnd.ts, 14, 31)) +>str : Symbol(str, Decl(contextualTypeTupleEnd.ts, 2, 38)) +>x : Symbol(x, Decl(contextualTypeTupleEnd.ts, 14, 31)) + +const a3: Funcs = [x => num(x), x => num(x), x => str(x)]; +>a3 : Symbol(a3, Decl(contextualTypeTupleEnd.ts, 15, 5)) +>Funcs : Symbol(Funcs, Decl(contextualTypeTupleEnd.ts, 0, 0)) +>x : Symbol(x, Decl(contextualTypeTupleEnd.ts, 15, 19)) +>num : Symbol(num, Decl(contextualTypeTupleEnd.ts, 0, 67)) +>x : Symbol(x, Decl(contextualTypeTupleEnd.ts, 15, 19)) +>x : Symbol(x, Decl(contextualTypeTupleEnd.ts, 15, 31)) +>num : Symbol(num, Decl(contextualTypeTupleEnd.ts, 0, 67)) +>x : Symbol(x, Decl(contextualTypeTupleEnd.ts, 15, 31)) +>x : Symbol(x, Decl(contextualTypeTupleEnd.ts, 15, 44)) +>str : Symbol(str, Decl(contextualTypeTupleEnd.ts, 2, 38)) +>x : Symbol(x, Decl(contextualTypeTupleEnd.ts, 15, 44)) + +// Repro from #43122 + +export type Selector = (state: State) => unknown; +>Selector : Symbol(Selector, Decl(contextualTypeTupleEnd.ts, 15, 58)) +>State : Symbol(State, Decl(contextualTypeTupleEnd.ts, 19, 21)) +>state : Symbol(state, Decl(contextualTypeTupleEnd.ts, 19, 31)) +>State : Symbol(State, Decl(contextualTypeTupleEnd.ts, 19, 21)) + +export type SelectorTuple = Selector[]; +>SelectorTuple : Symbol(SelectorTuple, Decl(contextualTypeTupleEnd.ts, 19, 56)) +>State : Symbol(State, Decl(contextualTypeTupleEnd.ts, 20, 26)) +>Selector : Symbol(Selector, Decl(contextualTypeTupleEnd.ts, 15, 58)) +>State : Symbol(State, Decl(contextualTypeTupleEnd.ts, 20, 26)) + +export type ExampleState = { +>ExampleState : Symbol(ExampleState, Decl(contextualTypeTupleEnd.ts, 20, 53)) + + foo: "foo"; +>foo : Symbol(foo, Decl(contextualTypeTupleEnd.ts, 22, 28)) + + bar: 42; +>bar : Symbol(bar, Decl(contextualTypeTupleEnd.ts, 23, 15)) + +}; + +export function createSelector>(...selectors: [...selectors: S, f: (x: any) => any]) { +>createSelector : Symbol(createSelector, Decl(contextualTypeTupleEnd.ts, 25, 2)) +>S : Symbol(S, Decl(contextualTypeTupleEnd.ts, 27, 31)) +>SelectorTuple : Symbol(SelectorTuple, Decl(contextualTypeTupleEnd.ts, 19, 56)) +>ExampleState : Symbol(ExampleState, Decl(contextualTypeTupleEnd.ts, 20, 53)) +>selectors : Symbol(selectors, Decl(contextualTypeTupleEnd.ts, 27, 70)) +>S : Symbol(S, Decl(contextualTypeTupleEnd.ts, 27, 31)) +>x : Symbol(x, Decl(contextualTypeTupleEnd.ts, 27, 106)) + + console.log(selectors); +>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --)) +>console : Symbol(console, Decl(lib.dom.d.ts, --, --)) +>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --)) +>selectors : Symbol(selectors, Decl(contextualTypeTupleEnd.ts, 27, 70)) +} + +createSelector( +>createSelector : Symbol(createSelector, Decl(contextualTypeTupleEnd.ts, 25, 2)) + + x => x.foo, +>x : Symbol(x, Decl(contextualTypeTupleEnd.ts, 31, 15)) +>x.foo : Symbol(foo, Decl(contextualTypeTupleEnd.ts, 22, 28)) +>x : Symbol(x, Decl(contextualTypeTupleEnd.ts, 31, 15)) +>foo : Symbol(foo, Decl(contextualTypeTupleEnd.ts, 22, 28)) + + x => x.bar, +>x : Symbol(x, Decl(contextualTypeTupleEnd.ts, 32, 15)) +>x.bar : Symbol(bar, Decl(contextualTypeTupleEnd.ts, 23, 15)) +>x : Symbol(x, Decl(contextualTypeTupleEnd.ts, 32, 15)) +>bar : Symbol(bar, Decl(contextualTypeTupleEnd.ts, 23, 15)) + + () => 42 +); + +// Repro from #43122 + +declare function example(...args: [...((n: number) => void)[], (x: any) => void]): void +>example : Symbol(example, Decl(contextualTypeTupleEnd.ts, 35, 2)) +>args : Symbol(args, Decl(contextualTypeTupleEnd.ts, 39, 25)) +>n : Symbol(n, Decl(contextualTypeTupleEnd.ts, 39, 40)) +>x : Symbol(x, Decl(contextualTypeTupleEnd.ts, 39, 64)) + +example( +>example : Symbol(example, Decl(contextualTypeTupleEnd.ts, 35, 2)) + + x => x.foo, // Error +>x : Symbol(x, Decl(contextualTypeTupleEnd.ts, 41, 8)) +>x : Symbol(x, Decl(contextualTypeTupleEnd.ts, 41, 8)) + + x => x.bar, // Error +>x : Symbol(x, Decl(contextualTypeTupleEnd.ts, 42, 15)) +>x : Symbol(x, Decl(contextualTypeTupleEnd.ts, 42, 15)) + + x => x.baz, +>x : Symbol(x, Decl(contextualTypeTupleEnd.ts, 43, 15)) +>x : Symbol(x, Decl(contextualTypeTupleEnd.ts, 43, 15)) + +); + +// Repro from #52846 + +declare function test(...args: [...((arg: number) => void)[], (arg: string) => void]): void; +>test : Symbol(test, Decl(contextualTypeTupleEnd.ts, 45, 2)) +>args : Symbol(args, Decl(contextualTypeTupleEnd.ts, 49, 22)) +>arg : Symbol(arg, Decl(contextualTypeTupleEnd.ts, 49, 37)) +>arg : Symbol(arg, Decl(contextualTypeTupleEnd.ts, 49, 63)) + +test(a => a, b => b, c => c); +>test : Symbol(test, Decl(contextualTypeTupleEnd.ts, 45, 2)) +>a : Symbol(a, Decl(contextualTypeTupleEnd.ts, 51, 5)) +>a : Symbol(a, Decl(contextualTypeTupleEnd.ts, 51, 5)) +>b : Symbol(b, Decl(contextualTypeTupleEnd.ts, 51, 12)) +>b : Symbol(b, Decl(contextualTypeTupleEnd.ts, 51, 12)) +>c : Symbol(c, Decl(contextualTypeTupleEnd.ts, 51, 20)) +>c : Symbol(c, Decl(contextualTypeTupleEnd.ts, 51, 20)) + diff --git a/tests/baselines/reference/contextualTypeTupleEnd.types b/tests/baselines/reference/contextualTypeTupleEnd.types new file mode 100644 index 0000000000000..6e2770b8a7430 --- /dev/null +++ b/tests/baselines/reference/contextualTypeTupleEnd.types @@ -0,0 +1,223 @@ +=== tests/cases/conformance/types/tuple/contextualTypeTupleEnd.ts === +type Funcs = [...((arg: number) => void)[], (arg: string) => void]; +>Funcs : [...((arg: number) => void)[], (arg: string) => void] +>arg : number +>arg : string + +declare function num(x: number): void; +>num : (x: number) => void +>x : number + +declare function str(x: string): void; +>str : (x: string) => void +>x : string + +declare function f1(...args: Funcs): void; +>f1 : (...args: Funcs) => void +>args : Funcs + +f1(); // Error +>f1() : void +>f1 : (...args: Funcs) => void + +f1(x => str(x)); +>f1(x => str(x)) : void +>f1 : (...args: Funcs) => void +>x => str(x) : (x: string) => void +>x : string +>str(x) : void +>str : (x: string) => void +>x : string + +f1(x => num(x), x => str(x)); +>f1(x => num(x), x => str(x)) : void +>f1 : (...args: Funcs) => void +>x => num(x) : (x: number) => void +>x : number +>num(x) : void +>num : (x: number) => void +>x : number +>x => str(x) : (x: string) => void +>x : string +>str(x) : void +>str : (x: string) => void +>x : string + +f1(x => num(x), x => num(x), x => str(x)); +>f1(x => num(x), x => num(x), x => str(x)) : void +>f1 : (...args: Funcs) => void +>x => num(x) : (x: number) => void +>x : number +>num(x) : void +>num : (x: number) => void +>x : number +>x => num(x) : (x: number) => void +>x : number +>num(x) : void +>num : (x: number) => void +>x : number +>x => str(x) : (x: string) => void +>x : string +>str(x) : void +>str : (x: string) => void +>x : string + +const a0: Funcs = []; // Error +>a0 : Funcs +>[] : [] + +const a1: Funcs = [x => str(x)]; +>a1 : Funcs +>[x => str(x)] : [(x: string) => void] +>x => str(x) : (x: string) => void +>x : string +>str(x) : void +>str : (x: string) => void +>x : string + +const a2: Funcs = [x => num(x), x => str(x)]; +>a2 : Funcs +>[x => num(x), x => str(x)] : [(x: number) => void, (x: string) => void] +>x => num(x) : (x: number) => void +>x : number +>num(x) : void +>num : (x: number) => void +>x : number +>x => str(x) : (x: string) => void +>x : string +>str(x) : void +>str : (x: string) => void +>x : string + +const a3: Funcs = [x => num(x), x => num(x), x => str(x)]; +>a3 : Funcs +>[x => num(x), x => num(x), x => str(x)] : [(x: number) => void, (x: number) => void, (x: string) => void] +>x => num(x) : (x: number) => void +>x : number +>num(x) : void +>num : (x: number) => void +>x : number +>x => num(x) : (x: number) => void +>x : number +>num(x) : void +>num : (x: number) => void +>x : number +>x => str(x) : (x: string) => void +>x : string +>str(x) : void +>str : (x: string) => void +>x : string + +// Repro from #43122 + +export type Selector = (state: State) => unknown; +>Selector : Selector +>state : State + +export type SelectorTuple = Selector[]; +>SelectorTuple : SelectorTuple + +export type ExampleState = { +>ExampleState : { foo: "foo"; bar: 42; } + + foo: "foo"; +>foo : "foo" + + bar: 42; +>bar : 42 + +}; + +export function createSelector>(...selectors: [...selectors: S, f: (x: any) => any]) { +>createSelector : >(...selectors: [...selectors: S, f: (x: any) => any]) => void +>selectors : [...selectors: S, f: (x: any) => any] +>x : any + + console.log(selectors); +>console.log(selectors) : void +>console.log : (...data: any[]) => void +>console : Console +>log : (...data: any[]) => void +>selectors : [...selectors: S, f: (x: any) => any] +} + +createSelector( +>createSelector( x => x.foo, x => x.bar, () => 42) : void +>createSelector : >(...selectors: [...selectors: S, f: (x: any) => any]) => void + + x => x.foo, +>x => x.foo : (x: ExampleState) => "foo" +>x : ExampleState +>x.foo : "foo" +>x : ExampleState +>foo : "foo" + + x => x.bar, +>x => x.bar : (x: ExampleState) => 42 +>x : ExampleState +>x.bar : 42 +>x : ExampleState +>bar : 42 + + () => 42 +>() => 42 : () => number +>42 : 42 + +); + +// Repro from #43122 + +declare function example(...args: [...((n: number) => void)[], (x: any) => void]): void +>example : (...args: [...((n: number) => void)[], (x: any) => void]) => void +>args : [...((n: number) => void)[], (x: any) => void] +>n : number +>x : any + +example( +>example( x => x.foo, // Error x => x.bar, // Error x => x.baz,) : void +>example : (...args: [...((n: number) => void)[], (x: any) => void]) => void + + x => x.foo, // Error +>x => x.foo : (x: number) => any +>x : number +>x.foo : any +>x : number +>foo : any + + x => x.bar, // Error +>x => x.bar : (x: number) => any +>x : number +>x.bar : any +>x : number +>bar : any + + x => x.baz, +>x => x.baz : (x: any) => any +>x : any +>x.baz : any +>x : any +>baz : any + +); + +// Repro from #52846 + +declare function test(...args: [...((arg: number) => void)[], (arg: string) => void]): void; +>test : (...args: [...((arg: number) => void)[], (arg: string) => void]) => void +>args : [...((arg: number) => void)[], (arg: string) => void] +>arg : number +>arg : string + +test(a => a, b => b, c => c); +>test(a => a, b => b, c => c) : void +>test : (...args: [...((arg: number) => void)[], (arg: string) => void]) => void +>a => a : (a: number) => number +>a : number +>a : number +>b => b : (b: number) => number +>b : number +>b : number +>c => c : (c: string) => string +>c : string +>c : string + diff --git a/tests/baselines/reference/narrowingByTypeofInSwitch.types b/tests/baselines/reference/narrowingByTypeofInSwitch.types index 95ec4201c888e..f88ae2f73fd8f 100644 --- a/tests/baselines/reference/narrowingByTypeofInSwitch.types +++ b/tests/baselines/reference/narrowingByTypeofInSwitch.types @@ -551,7 +551,7 @@ function multipleGenericFuse(xy: X | case 'function': return [xy, 1]; >'function' : "function" ->[xy, 1] : [X & Function, 1] +>[xy, 1] : [X & Function, number] >xy : X & Function >1 : 1 @@ -1091,7 +1091,7 @@ function multipleGenericFuseWithBoth case `function`: return [xy, 1]; >`function` : "function" ->[xy, 1] : [X & Function, 1] +>[xy, 1] : [X & Function, number] >xy : X & Function >1 : 1 diff --git a/tests/baselines/reference/spreadsAndContextualTupleTypes.types b/tests/baselines/reference/spreadsAndContextualTupleTypes.types index 5224eb8debf15..86f875acf4cde 100644 --- a/tests/baselines/reference/spreadsAndContextualTupleTypes.types +++ b/tests/baselines/reference/spreadsAndContextualTupleTypes.types @@ -33,9 +33,9 @@ fx1([...t3, 'a']); >'a' : "a" fx2(['x', 'y', 'z', 'a']); ->fx2(['x', 'y', 'z', 'a']) : ["x", "y", "z", "a"] +>fx2(['x', 'y', 'z', 'a']) : [string, string, string, "a"] >fx2 : (x: T) => T ->['x', 'y', 'z', 'a'] : ["x", "y", "z", "a"] +>['x', 'y', 'z', 'a'] : [string, string, string, "a"] >'x' : "x" >'y' : "y" >'z' : "z" @@ -56,7 +56,7 @@ const x1: [...string[], '!'] = ['!']; const x2: [...string[], '!'] = ['a', '!']; >x2 : [...string[], "!"] ->['a', '!'] : ["a", "!"] +>['a', '!'] : [string, "!"] >'a' : "a" >'!' : "!" diff --git a/tests/baselines/reference/variadicTuples1.errors.txt b/tests/baselines/reference/variadicTuples1.errors.txt index 5cabf29b9e794..7058df28394e4 100644 --- a/tests/baselines/reference/variadicTuples1.errors.txt +++ b/tests/baselines/reference/variadicTuples1.errors.txt @@ -36,7 +36,7 @@ tests/cases/conformance/types/tuple/variadicTuples1.ts(191,5): error TS2322: Typ tests/cases/conformance/types/tuple/variadicTuples1.ts(203,5): error TS2322: Type 'string' is not assignable to type 'keyof [1, 2, ...T]'. Type '"2"' is not assignable to type '"0" | "1" | keyof T[]'. tests/cases/conformance/types/tuple/variadicTuples1.ts(357,26): error TS2322: Type 'string' is not assignable to type 'number'. -tests/cases/conformance/types/tuple/variadicTuples1.ts(397,7): error TS2322: Type '[false, false]' is not assignable to type '[...number[], boolean]'. +tests/cases/conformance/types/tuple/variadicTuples1.ts(397,7): error TS2322: Type '[boolean, false]' is not assignable to type '[...number[], boolean]'. Type at position 0 in source is not compatible with type at position 0 in target. Type 'boolean' is not assignable to type 'number'. @@ -498,7 +498,7 @@ tests/cases/conformance/types/tuple/variadicTuples1.ts(397,7): error TS2322: Typ type Unbounded = [...Numbers, boolean]; const data: Unbounded = [false, false]; // Error ~~~~ -!!! error TS2322: Type '[false, false]' is not assignable to type '[...number[], boolean]'. +!!! error TS2322: Type '[boolean, false]' is not assignable to type '[...number[], boolean]'. !!! error TS2322: Type at position 0 in source is not compatible with type at position 0 in target. !!! error TS2322: Type 'boolean' is not assignable to type 'number'. diff --git a/tests/baselines/reference/variadicTuples1.types b/tests/baselines/reference/variadicTuples1.types index 33b04d826e0f7..86b88f9e5223f 100644 --- a/tests/baselines/reference/variadicTuples1.types +++ b/tests/baselines/reference/variadicTuples1.types @@ -1397,7 +1397,7 @@ type Unbounded = [...Numbers, boolean]; const data: Unbounded = [false, false]; // Error >data : [...number[], boolean] ->[false, false] : [false, false] +>[false, false] : [boolean, false] >false : false >false : false diff --git a/tests/baselines/reference/variadicTuples2.errors.txt b/tests/baselines/reference/variadicTuples2.errors.txt index 55cc6d5f66f4d..e68fc8bbed9eb 100644 --- a/tests/baselines/reference/variadicTuples2.errors.txt +++ b/tests/baselines/reference/variadicTuples2.errors.txt @@ -45,7 +45,7 @@ tests/cases/conformance/types/tuple/variadicTuples2.ts(74,5): error TS2322: Type tests/cases/conformance/types/tuple/variadicTuples2.ts(79,5): error TS2322: Type '[number, string, ...any[]]' is not assignable to type '[number, ...number[]]'. Type at positions 1 through 2 in source is not compatible with type at position 1 in target. Type 'string' is not assignable to type 'number'. -tests/cases/conformance/types/tuple/variadicTuples2.ts(111,16): error TS2345: Argument of type '[1, 2, 3, 4]' is not assignable to parameter of type '[...number[], (...values: number[]) => void]'. +tests/cases/conformance/types/tuple/variadicTuples2.ts(111,16): error TS2345: Argument of type '[1, 2, 3, number]' is not assignable to parameter of type '[...number[], (...values: number[]) => void]'. Type at position 3 in source is not compatible with type at position 1 in target. Type 'number' is not assignable to type '(...values: number[]) => void'. tests/cases/conformance/types/tuple/variadicTuples2.ts(112,6): error TS2345: Argument of type 'string[]' is not assignable to parameter of type '[...string[], (...values: string[]) => void]'. @@ -245,7 +245,7 @@ tests/cases/conformance/types/tuple/variadicTuples2.ts(134,25): error TS2345: Ar pipe(1, 2, 3, 4); // Error ~~~~~~~~~~ -!!! error TS2345: Argument of type '[1, 2, 3, 4]' is not assignable to parameter of type '[...number[], (...values: number[]) => void]'. +!!! error TS2345: Argument of type '[1, 2, 3, number]' is not assignable to parameter of type '[...number[], (...values: number[]) => void]'. !!! error TS2345: Type at position 3 in source is not compatible with type at position 1 in target. !!! error TS2345: Type 'number' is not assignable to type '(...values: number[]) => void'. pipe(...sa); // Error diff --git a/tests/cases/conformance/types/tuple/contextualTypeTupleEnd.ts b/tests/cases/conformance/types/tuple/contextualTypeTupleEnd.ts new file mode 100644 index 0000000000000..0670992de39e0 --- /dev/null +++ b/tests/cases/conformance/types/tuple/contextualTypeTupleEnd.ts @@ -0,0 +1,55 @@ +// @strict: true +// @noEmit: true + +type Funcs = [...((arg: number) => void)[], (arg: string) => void]; + +declare function num(x: number): void; +declare function str(x: string): void; + +declare function f1(...args: Funcs): void; + +f1(); // Error +f1(x => str(x)); +f1(x => num(x), x => str(x)); +f1(x => num(x), x => num(x), x => str(x)); + +const a0: Funcs = []; // Error +const a1: Funcs = [x => str(x)]; +const a2: Funcs = [x => num(x), x => str(x)]; +const a3: Funcs = [x => num(x), x => num(x), x => str(x)]; + +// Repro from #43122 + +export type Selector = (state: State) => unknown; +export type SelectorTuple = Selector[]; + +export type ExampleState = { + foo: "foo"; + bar: 42; +}; + +export function createSelector>(...selectors: [...selectors: S, f: (x: any) => any]) { + console.log(selectors); +} + +createSelector( + x => x.foo, + x => x.bar, + () => 42 +); + +// Repro from #43122 + +declare function example(...args: [...((n: number) => void)[], (x: any) => void]): void + +example( + x => x.foo, // Error + x => x.bar, // Error + x => x.baz, +); + +// Repro from #52846 + +declare function test(...args: [...((arg: number) => void)[], (arg: string) => void]): void; + +test(a => a, b => b, c => c);