diff --git a/internal/checker/checker.go b/internal/checker/checker.go index b639d488e44..c55b43a24a2 100644 --- a/internal/checker/checker.go +++ b/internal/checker/checker.go @@ -16441,7 +16441,12 @@ func (c *Checker) getNonMissingTypeOfSymbol(symbol *ast.Symbol) *Type { func (c *Checker) getTypeOfInstantiatedSymbol(symbol *ast.Symbol) *Type { links := c.valueSymbolLinks.Get(symbol) if links.resolvedType == nil { - links.resolvedType = c.instantiateType(c.getTypeOfSymbol(links.target), links.mapper) + declaration := links.target.ValueDeclaration + t := c.instantiateType(c.getTypeOfSymbol(links.target), links.mapper) + if declaration != nil && ast.IsParameterDeclaration(declaration) && hasDotDotDotToken(declaration) { + t = c.normalizeNoInferSpread(t) + } + links.resolvedType = t } return links.resolvedType } @@ -16518,9 +16523,14 @@ func (c *Checker) getTypeOfVariableOrParameterOrPropertyWorker(symbol *ast.Symbo } var result *Type switch declaration.Kind { - case ast.KindParameter, ast.KindPropertyDeclaration, ast.KindPropertySignature, ast.KindVariableDeclaration, + case ast.KindPropertyDeclaration, ast.KindPropertySignature, ast.KindVariableDeclaration, ast.KindBindingElement: result = c.getWidenedTypeForVariableLikeDeclaration(declaration, true /*reportErrors*/) + case ast.KindParameter: + result = c.getWidenedTypeForVariableLikeDeclaration(declaration, true /*reportErrors*/) + if hasDotDotDotToken(declaration) { + result = c.normalizeNoInferSpread(result) + } case ast.KindPropertyAssignment: result = c.checkPropertyAssignment(declaration, CheckModeNormal) case ast.KindShorthandPropertyAssignment: @@ -23215,6 +23225,12 @@ func (c *Checker) createNormalizedTupleTypeEx(target *Type, elementTypes []*Type return c.createTypeReferenceEx(target, elementTypes, objectFlags) } if d.combinedFlags&ElementFlagsVariadic != 0 { + elementTypes = core.SameMapIndex(elementTypes, func(t *Type, i int) *Type { + if i < len(d.elementInfos) && d.elementInfos[i].flags&ElementFlagsVariadic != 0 { + return c.normalizeNoInferSpread(t) + } + return t + }) for i, e := range elementTypes { if i < len(d.elementInfos) && d.elementInfos[i].flags&ElementFlagsVariadic != 0 && e.flags&(TypeFlagsNever|TypeFlagsUnion) != 0 { // Transform [A, ...(X | Y | Z)] into [A, ...X] | [A, ...Y] | [A, ...Z] @@ -23256,6 +23272,19 @@ func (c *Checker) createNormalizedTupleTypeEx(target *Type, elementTypes []*Type return tupleTarget } +func (c *Checker) normalizeNoInferSpread(t *Type) *Type { + if !c.isNoInferType(t) { + return t + } + return c.mapType(t.AsSubstitutionType().baseType, func(element *Type) *Type { + if !isTupleType(element) { + return c.getNoInferType(t) + } + target := element.TargetTupleType() + return c.createTupleTypeEx(core.Map(c.getElementTypes(element), c.getNoInferType), target.elementInfos, target.readonly) + }) +} + func (c *Checker) createNormalizedTupleType(target *Type, elementTypes []*Type) *Type { return c.createNormalizedTupleTypeEx(target, elementTypes, ObjectFlagsNone) } diff --git a/testdata/baselines/reference/conformance/noInferRestSpread1.errors.txt b/testdata/baselines/reference/conformance/noInferRestSpread1.errors.txt new file mode 100644 index 00000000000..21f67ac0e0a --- /dev/null +++ b/testdata/baselines/reference/conformance/noInferRestSpread1.errors.txt @@ -0,0 +1,41 @@ +noInferRestSpread1.ts(7,22): error TS2345: Argument of type '(a: number, b: number) => void' is not assignable to parameter of type '(args_0: number) => void'. + Target signature provides too few arguments. Expected 2 or more, but got 1. + + +==== noInferRestSpread1.ts (1 errors) ==== + declare function call( + arg: (...args: NoInfer) => void, + ...args: A + ): A; + + const result1 = call((a: number) => {}, 1, 2); + const result2 = call((a: number, b: number) => {}, 1); // error + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2345: Argument of type '(a: number, b: number) => void' is not assignable to parameter of type '(args_0: number) => void'. +!!! error TS2345: Target signature provides too few arguments. Expected 2 or more, but got 1. + const result3 = call((a) => {}, 1, ''); // test contextual parameters + const result4 = call((a, b) => {}, 1, ''); // test contextual parameters + const result5 = call((...args) => {}, 1, ''); // test contextual parameters + const result6 = call((a, ...rest) => {}, 1, ''); // test contextual parameters + + declare function fn1( + cb: (a: [number, ...NoInfer]) => void, + args: A, + ): A; + + declare const singleStr: [string]; + + const result7 = fn1((arg) => { + arg.length; + }, singleStr); + + declare const tupleUnion: [string] | [number, boolean]; + + const result8 = fn1((arg) => { + arg.length; + }, tupleUnion); + + declare function fn2(arg: (...args: NoInfer<[string, number]>) => void): void; + + fn2((a, ...rest) => {}); + \ No newline at end of file diff --git a/testdata/baselines/reference/conformance/noInferRestSpread1.symbols b/testdata/baselines/reference/conformance/noInferRestSpread1.symbols new file mode 100644 index 00000000000..18dc968f1ab --- /dev/null +++ b/testdata/baselines/reference/conformance/noInferRestSpread1.symbols @@ -0,0 +1,113 @@ +//// [tests/cases/conformance/types/typeRelationships/typeInference/noInferRestSpread1.ts] //// + +=== noInferRestSpread1.ts === +declare function call( +>call : Symbol(call, Decl(noInferRestSpread1.ts, 0, 0)) +>A : Symbol(A, Decl(noInferRestSpread1.ts, 0, 22)) + + arg: (...args: NoInfer) => void, +>arg : Symbol(arg, Decl(noInferRestSpread1.ts, 0, 52)) +>args : Symbol(args, Decl(noInferRestSpread1.ts, 1, 8)) +>NoInfer : Symbol(NoInfer, Decl(lib.es5.d.ts, --, --)) +>A : Symbol(A, Decl(noInferRestSpread1.ts, 0, 22)) + + ...args: A +>args : Symbol(args, Decl(noInferRestSpread1.ts, 1, 37)) +>A : Symbol(A, Decl(noInferRestSpread1.ts, 0, 22)) + +): A; +>A : Symbol(A, Decl(noInferRestSpread1.ts, 0, 22)) + +const result1 = call((a: number) => {}, 1, 2); +>result1 : Symbol(result1, Decl(noInferRestSpread1.ts, 5, 5)) +>call : Symbol(call, Decl(noInferRestSpread1.ts, 0, 0)) +>a : Symbol(a, Decl(noInferRestSpread1.ts, 5, 22)) + +const result2 = call((a: number, b: number) => {}, 1); // error +>result2 : Symbol(result2, Decl(noInferRestSpread1.ts, 6, 5)) +>call : Symbol(call, Decl(noInferRestSpread1.ts, 0, 0)) +>a : Symbol(a, Decl(noInferRestSpread1.ts, 6, 22)) +>b : Symbol(b, Decl(noInferRestSpread1.ts, 6, 32)) + +const result3 = call((a) => {}, 1, ''); // test contextual parameters +>result3 : Symbol(result3, Decl(noInferRestSpread1.ts, 7, 5)) +>call : Symbol(call, Decl(noInferRestSpread1.ts, 0, 0)) +>a : Symbol(a, Decl(noInferRestSpread1.ts, 7, 22)) + +const result4 = call((a, b) => {}, 1, ''); // test contextual parameters +>result4 : Symbol(result4, Decl(noInferRestSpread1.ts, 8, 5)) +>call : Symbol(call, Decl(noInferRestSpread1.ts, 0, 0)) +>a : Symbol(a, Decl(noInferRestSpread1.ts, 8, 22)) +>b : Symbol(b, Decl(noInferRestSpread1.ts, 8, 24)) + +const result5 = call((...args) => {}, 1, ''); // test contextual parameters +>result5 : Symbol(result5, Decl(noInferRestSpread1.ts, 9, 5)) +>call : Symbol(call, Decl(noInferRestSpread1.ts, 0, 0)) +>args : Symbol(args, Decl(noInferRestSpread1.ts, 9, 22)) + +const result6 = call((a, ...rest) => {}, 1, ''); // test contextual parameters +>result6 : Symbol(result6, Decl(noInferRestSpread1.ts, 10, 5)) +>call : Symbol(call, Decl(noInferRestSpread1.ts, 0, 0)) +>a : Symbol(a, Decl(noInferRestSpread1.ts, 10, 22)) +>rest : Symbol(rest, Decl(noInferRestSpread1.ts, 10, 24)) + +declare function fn1( +>fn1 : Symbol(fn1, Decl(noInferRestSpread1.ts, 10, 48)) +>A : Symbol(A, Decl(noInferRestSpread1.ts, 12, 21)) + + cb: (a: [number, ...NoInfer]) => void, +>cb : Symbol(cb, Decl(noInferRestSpread1.ts, 12, 42)) +>a : Symbol(a, Decl(noInferRestSpread1.ts, 13, 7)) +>NoInfer : Symbol(NoInfer, Decl(lib.es5.d.ts, --, --)) +>A : Symbol(A, Decl(noInferRestSpread1.ts, 12, 21)) + + args: A, +>args : Symbol(args, Decl(noInferRestSpread1.ts, 13, 43)) +>A : Symbol(A, Decl(noInferRestSpread1.ts, 12, 21)) + +): A; +>A : Symbol(A, Decl(noInferRestSpread1.ts, 12, 21)) + +declare const singleStr: [string]; +>singleStr : Symbol(singleStr, Decl(noInferRestSpread1.ts, 17, 13)) + +const result7 = fn1((arg) => { +>result7 : Symbol(result7, Decl(noInferRestSpread1.ts, 19, 5)) +>fn1 : Symbol(fn1, Decl(noInferRestSpread1.ts, 10, 48)) +>arg : Symbol(arg, Decl(noInferRestSpread1.ts, 19, 21)) + + arg.length; +>arg.length : Symbol(length) +>arg : Symbol(arg, Decl(noInferRestSpread1.ts, 19, 21)) +>length : Symbol(length) + +}, singleStr); +>singleStr : Symbol(singleStr, Decl(noInferRestSpread1.ts, 17, 13)) + +declare const tupleUnion: [string] | [number, boolean]; +>tupleUnion : Symbol(tupleUnion, Decl(noInferRestSpread1.ts, 23, 13)) + +const result8 = fn1((arg) => { +>result8 : Symbol(result8, Decl(noInferRestSpread1.ts, 25, 5)) +>fn1 : Symbol(fn1, Decl(noInferRestSpread1.ts, 10, 48)) +>arg : Symbol(arg, Decl(noInferRestSpread1.ts, 25, 21)) + + arg.length; +>arg.length : Symbol(length) +>arg : Symbol(arg, Decl(noInferRestSpread1.ts, 25, 21)) +>length : Symbol(length) + +}, tupleUnion); +>tupleUnion : Symbol(tupleUnion, Decl(noInferRestSpread1.ts, 23, 13)) + +declare function fn2(arg: (...args: NoInfer<[string, number]>) => void): void; +>fn2 : Symbol(fn2, Decl(noInferRestSpread1.ts, 27, 15)) +>arg : Symbol(arg, Decl(noInferRestSpread1.ts, 29, 21)) +>args : Symbol(args, Decl(noInferRestSpread1.ts, 29, 27)) +>NoInfer : Symbol(NoInfer, Decl(lib.es5.d.ts, --, --)) + +fn2((a, ...rest) => {}); +>fn2 : Symbol(fn2, Decl(noInferRestSpread1.ts, 27, 15)) +>a : Symbol(a, Decl(noInferRestSpread1.ts, 31, 5)) +>rest : Symbol(rest, Decl(noInferRestSpread1.ts, 31, 7)) + diff --git a/testdata/baselines/reference/conformance/noInferRestSpread1.types b/testdata/baselines/reference/conformance/noInferRestSpread1.types new file mode 100644 index 00000000000..732799eb52a --- /dev/null +++ b/testdata/baselines/reference/conformance/noInferRestSpread1.types @@ -0,0 +1,131 @@ +//// [tests/cases/conformance/types/typeRelationships/typeInference/noInferRestSpread1.ts] //// + +=== noInferRestSpread1.ts === +declare function call( +>call : (arg: (...args: NoInfer) => void, ...args: A) => A + + arg: (...args: NoInfer) => void, +>arg : (...args: NoInfer) => void +>args : NoInfer + + ...args: A +>args : A + +): A; + +const result1 = call((a: number) => {}, 1, 2); +>result1 : [number, number] +>call((a: number) => {}, 1, 2) : [number, number] +>call : (arg: (...args: NoInfer) => void, ...args: A) => A +>(a: number) => {} : (a: number) => void +>a : number +>1 : 1 +>2 : 2 + +const result2 = call((a: number, b: number) => {}, 1); // error +>result2 : [number] +>call((a: number, b: number) => {}, 1) : [number] +>call : (arg: (...args: NoInfer) => void, ...args: A) => A +>(a: number, b: number) => {} : (a: number, b: number) => void +>a : number +>b : number +>1 : 1 + +const result3 = call((a) => {}, 1, ''); // test contextual parameters +>result3 : [number, string] +>call((a) => {}, 1, '') : [number, string] +>call : (arg: (...args: NoInfer) => void, ...args: A) => A +>(a) => {} : (a: number) => void +>a : number +>1 : 1 +>'' : "" + +const result4 = call((a, b) => {}, 1, ''); // test contextual parameters +>result4 : [number, string] +>call((a, b) => {}, 1, '') : [number, string] +>call : (arg: (...args: NoInfer) => void, ...args: A) => A +>(a, b) => {} : (a: number, b: string) => void +>a : number +>b : string +>1 : 1 +>'' : "" + +const result5 = call((...args) => {}, 1, ''); // test contextual parameters +>result5 : [number, string] +>call((...args) => {}, 1, '') : [number, string] +>call : (arg: (...args: NoInfer) => void, ...args: A) => A +>(...args) => {} : (args_0: number, args_1: string) => void +>args : [number, string] +>1 : 1 +>'' : "" + +const result6 = call((a, ...rest) => {}, 1, ''); // test contextual parameters +>result6 : [number, string] +>call((a, ...rest) => {}, 1, '') : [number, string] +>call : (arg: (...args: NoInfer) => void, ...args: A) => A +>(a, ...rest) => {} : (a: number, rest_0: string) => void +>a : number +>rest : [string] +>1 : 1 +>'' : "" + +declare function fn1( +>fn1 : (cb: (a: [number, ...NoInfer]) => void, args: A) => A + + cb: (a: [number, ...NoInfer]) => void, +>cb : (a: [number, ...NoInfer]) => void +>a : [number, ...NoInfer] + + args: A, +>args : A + +): A; + +declare const singleStr: [string]; +>singleStr : [string] + +const result7 = fn1((arg) => { +>result7 : [string] +>fn1((arg) => { arg.length;}, singleStr) : [string] +>fn1 : (cb: (a: [number, ...NoInfer]) => void, args: A) => A +>(arg) => { arg.length;} : (arg: [number, string]) => void +>arg : [number, string] + + arg.length; +>arg.length : 2 +>arg : [number, string] +>length : 2 + +}, singleStr); +>singleStr : [string] + +declare const tupleUnion: [string] | [number, boolean]; +>tupleUnion : [string] | [number, boolean] + +const result8 = fn1((arg) => { +>result8 : [string] | [number, boolean] +>fn1((arg) => { arg.length;}, tupleUnion) : [string] | [number, boolean] +>fn1 : (cb: (a: [number, ...NoInfer]) => void, args: A) => A +>(arg) => { arg.length;} : (arg: [number, string] | [number, number, boolean]) => void +>arg : [number, string] | [number, number, boolean] + + arg.length; +>arg.length : 2 | 3 +>arg : [number, string] | [number, number, boolean] +>length : 2 | 3 + +}, tupleUnion); +>tupleUnion : [string] | [number, boolean] + +declare function fn2(arg: (...args: NoInfer<[string, number]>) => void): void; +>fn2 : (arg: (...args: NoInfer<[string, number]>) => void) => void +>arg : (args_0: string, args_1: number) => void +>args : [string, number] + +fn2((a, ...rest) => {}); +>fn2((a, ...rest) => {}) : void +>fn2 : (arg: (...args: NoInfer<[string, number]>) => void) => void +>(a, ...rest) => {} : (a: string, rest_0: number) => void +>a : string +>rest : [number] + diff --git a/testdata/baselines/reference/conformance/noInferRestSpread2.symbols b/testdata/baselines/reference/conformance/noInferRestSpread2.symbols new file mode 100644 index 00000000000..67eeffa1d18 --- /dev/null +++ b/testdata/baselines/reference/conformance/noInferRestSpread2.symbols @@ -0,0 +1,106 @@ +//// [tests/cases/conformance/types/typeRelationships/typeInference/noInferRestSpread2.ts] //// + +=== noInferRestSpread2.ts === +// https://github.com/microsoft/TypeScript/issues/63627 + +function arr1(a: [number, ...NoInfer<[]>]) {} +>arr1 : Symbol(arr1, Decl(noInferRestSpread2.ts, 0, 0)) +>a : Symbol(a, Decl(noInferRestSpread2.ts, 2, 14)) +>NoInfer : Symbol(NoInfer, Decl(lib.es5.d.ts, --, --)) + +arr1([1]); +>arr1 : Symbol(arr1, Decl(noInferRestSpread2.ts, 0, 0)) + +function arr2(a: [number, ...[]]) {} +>arr2 : Symbol(arr2, Decl(noInferRestSpread2.ts, 3, 10)) +>a : Symbol(a, Decl(noInferRestSpread2.ts, 5, 14)) + +arr2([1]); +>arr2 : Symbol(arr2, Decl(noInferRestSpread2.ts, 3, 10)) + +function fun1(a: (x: number, ...o: NoInfer<[]>) => void) {} +>fun1 : Symbol(fun1, Decl(noInferRestSpread2.ts, 6, 10)) +>a : Symbol(a, Decl(noInferRestSpread2.ts, 8, 14)) +>x : Symbol(x, Decl(noInferRestSpread2.ts, 8, 18)) +>o : Symbol(o, Decl(noInferRestSpread2.ts, 8, 28)) +>NoInfer : Symbol(NoInfer, Decl(lib.es5.d.ts, --, --)) + +fun1(x => {}); +>fun1 : Symbol(fun1, Decl(noInferRestSpread2.ts, 6, 10)) +>x : Symbol(x, Decl(noInferRestSpread2.ts, 9, 5)) + +function fun2(a: (x: number, ...o: []) => void) {} +>fun2 : Symbol(fun2, Decl(noInferRestSpread2.ts, 9, 14)) +>a : Symbol(a, Decl(noInferRestSpread2.ts, 11, 14)) +>x : Symbol(x, Decl(noInferRestSpread2.ts, 11, 18)) +>o : Symbol(o, Decl(noInferRestSpread2.ts, 11, 28)) + +fun2(x => {}); +>fun2 : Symbol(fun2, Decl(noInferRestSpread2.ts, 9, 14)) +>x : Symbol(x, Decl(noInferRestSpread2.ts, 12, 5)) + +function func1( +>func1 : Symbol(func1, Decl(noInferRestSpread2.ts, 12, 14)) +>A : Symbol(A, Decl(noInferRestSpread2.ts, 14, 15)) + + args: A, +>args : Symbol(args, Decl(noInferRestSpread2.ts, 14, 36)) +>A : Symbol(A, Decl(noInferRestSpread2.ts, 14, 15)) + + fn: (x: number, ...args: NoInfer) => void, +>fn : Symbol(fn, Decl(noInferRestSpread2.ts, 15, 10)) +>x : Symbol(x, Decl(noInferRestSpread2.ts, 16, 7)) +>args : Symbol(args, Decl(noInferRestSpread2.ts, 16, 17)) +>NoInfer : Symbol(NoInfer, Decl(lib.es5.d.ts, --, --)) +>A : Symbol(A, Decl(noInferRestSpread2.ts, 14, 15)) + +) {} + +func1([] as const, x => {}); +>func1 : Symbol(func1, Decl(noInferRestSpread2.ts, 12, 14)) +>const : Symbol(const) +>x : Symbol(x, Decl(noInferRestSpread2.ts, 19, 18)) + +function func2( +>func2 : Symbol(func2, Decl(noInferRestSpread2.ts, 19, 28)) +>A : Symbol(A, Decl(noInferRestSpread2.ts, 21, 15)) + + args: A, +>args : Symbol(args, Decl(noInferRestSpread2.ts, 21, 36)) +>A : Symbol(A, Decl(noInferRestSpread2.ts, 21, 15)) + + fn: (...args: NoInfer) => void, +>fn : Symbol(fn, Decl(noInferRestSpread2.ts, 22, 10)) +>args : Symbol(args, Decl(noInferRestSpread2.ts, 23, 7)) +>NoInfer : Symbol(NoInfer, Decl(lib.es5.d.ts, --, --)) +>A : Symbol(A, Decl(noInferRestSpread2.ts, 21, 15)) + +) {} + +function foo(u: number, v: number) { +>foo : Symbol(foo, Decl(noInferRestSpread2.ts, 24, 4)) +>u : Symbol(u, Decl(noInferRestSpread2.ts, 26, 13)) +>v : Symbol(v, Decl(noInferRestSpread2.ts, 26, 23)) + + func2([u, v] as const, () => {}); +>func2 : Symbol(func2, Decl(noInferRestSpread2.ts, 19, 28)) +>u : Symbol(u, Decl(noInferRestSpread2.ts, 26, 13)) +>v : Symbol(v, Decl(noInferRestSpread2.ts, 26, 23)) +>const : Symbol(const) + + func2([u, v] as const, (x: number) => {}); +>func2 : Symbol(func2, Decl(noInferRestSpread2.ts, 19, 28)) +>u : Symbol(u, Decl(noInferRestSpread2.ts, 26, 13)) +>v : Symbol(v, Decl(noInferRestSpread2.ts, 26, 23)) +>const : Symbol(const) +>x : Symbol(x, Decl(noInferRestSpread2.ts, 28, 26)) + + func2([u, v] as const, (x: number, y: number) => {}); +>func2 : Symbol(func2, Decl(noInferRestSpread2.ts, 19, 28)) +>u : Symbol(u, Decl(noInferRestSpread2.ts, 26, 13)) +>v : Symbol(v, Decl(noInferRestSpread2.ts, 26, 23)) +>const : Symbol(const) +>x : Symbol(x, Decl(noInferRestSpread2.ts, 29, 26)) +>y : Symbol(y, Decl(noInferRestSpread2.ts, 29, 36)) +} + diff --git a/testdata/baselines/reference/conformance/noInferRestSpread2.types b/testdata/baselines/reference/conformance/noInferRestSpread2.types new file mode 100644 index 00000000000..cbba8a94908 --- /dev/null +++ b/testdata/baselines/reference/conformance/noInferRestSpread2.types @@ -0,0 +1,118 @@ +//// [tests/cases/conformance/types/typeRelationships/typeInference/noInferRestSpread2.ts] //// + +=== noInferRestSpread2.ts === +// https://github.com/microsoft/TypeScript/issues/63627 + +function arr1(a: [number, ...NoInfer<[]>]) {} +>arr1 : (a: [number, ...NoInfer<[]>]) => void +>a : [number] + +arr1([1]); +>arr1([1]) : void +>arr1 : (a: [number, ...NoInfer<[]>]) => void +>[1] : [number] +>1 : 1 + +function arr2(a: [number, ...[]]) {} +>arr2 : (a: [number, ...[]]) => void +>a : [number] + +arr2([1]); +>arr2([1]) : void +>arr2 : (a: [number, ...[]]) => void +>[1] : [number] +>1 : 1 + +function fun1(a: (x: number, ...o: NoInfer<[]>) => void) {} +>fun1 : (a: (x: number, ...o: NoInfer<[]>) => void) => void +>a : (x: number) => void +>x : number +>o : [] + +fun1(x => {}); +>fun1(x => {}) : void +>fun1 : (a: (x: number, ...o: NoInfer<[]>) => void) => void +>x => {} : (x: number) => void +>x : number + +function fun2(a: (x: number, ...o: []) => void) {} +>fun2 : (a: (x: number, ...o: []) => void) => void +>a : (x: number) => void +>x : number +>o : [] + +fun2(x => {}); +>fun2(x => {}) : void +>fun2 : (a: (x: number, ...o: []) => void) => void +>x => {} : (x: number) => void +>x : number + +function func1( +>func1 : (args: A, fn: (x: number, ...args: NoInfer) => void) => void + + args: A, +>args : A + + fn: (x: number, ...args: NoInfer) => void, +>fn : (x: number, ...args: NoInfer) => void +>x : number +>args : NoInfer + +) {} + +func1([] as const, x => {}); +>func1([] as const, x => {}) : void +>func1 : (args: A, fn: (x: number, ...args: NoInfer) => void) => void +>[] as const : [] +>[] : [] +>x => {} : (x: number) => void +>x : number + +function func2( +>func2 : (args: A, fn: (...args: NoInfer) => void) => void + + args: A, +>args : A + + fn: (...args: NoInfer) => void, +>fn : (...args: NoInfer) => void +>args : NoInfer + +) {} + +function foo(u: number, v: number) { +>foo : (u: number, v: number) => void +>u : number +>v : number + + func2([u, v] as const, () => {}); +>func2([u, v] as const, () => {}) : void +>func2 : (args: A, fn: (...args: NoInfer) => void) => void +>[u, v] as const : [number, number] +>[u, v] : [number, number] +>u : number +>v : number +>() => {} : () => void + + func2([u, v] as const, (x: number) => {}); +>func2([u, v] as const, (x: number) => {}) : void +>func2 : (args: A, fn: (...args: NoInfer) => void) => void +>[u, v] as const : [number, number] +>[u, v] : [number, number] +>u : number +>v : number +>(x: number) => {} : (x: number) => void +>x : number + + func2([u, v] as const, (x: number, y: number) => {}); +>func2([u, v] as const, (x: number, y: number) => {}) : void +>func2 : (args: A, fn: (...args: NoInfer) => void) => void +>[u, v] as const : [number, number] +>[u, v] : [number, number] +>u : number +>v : number +>(x: number, y: number) => {} : (x: number, y: number) => void +>x : number +>y : number +} + diff --git a/testdata/tests/cases/conformance/types/typeRelationships/typeInference/noInferRestSpread1.ts b/testdata/tests/cases/conformance/types/typeRelationships/typeInference/noInferRestSpread1.ts new file mode 100644 index 00000000000..c86f2ec235a --- /dev/null +++ b/testdata/tests/cases/conformance/types/typeRelationships/typeInference/noInferRestSpread1.ts @@ -0,0 +1,35 @@ +// @strict: true +// @noEmit: true + +declare function call( + arg: (...args: NoInfer) => void, + ...args: A +): A; + +const result1 = call((a: number) => {}, 1, 2); +const result2 = call((a: number, b: number) => {}, 1); // error +const result3 = call((a) => {}, 1, ''); // test contextual parameters +const result4 = call((a, b) => {}, 1, ''); // test contextual parameters +const result5 = call((...args) => {}, 1, ''); // test contextual parameters +const result6 = call((a, ...rest) => {}, 1, ''); // test contextual parameters + +declare function fn1( + cb: (a: [number, ...NoInfer]) => void, + args: A, +): A; + +declare const singleStr: [string]; + +const result7 = fn1((arg) => { + arg.length; +}, singleStr); + +declare const tupleUnion: [string] | [number, boolean]; + +const result8 = fn1((arg) => { + arg.length; +}, tupleUnion); + +declare function fn2(arg: (...args: NoInfer<[string, number]>) => void): void; + +fn2((a, ...rest) => {}); diff --git a/testdata/tests/cases/conformance/types/typeRelationships/typeInference/noInferRestSpread2.ts b/testdata/tests/cases/conformance/types/typeRelationships/typeInference/noInferRestSpread2.ts new file mode 100644 index 00000000000..948777ec0cb --- /dev/null +++ b/testdata/tests/cases/conformance/types/typeRelationships/typeInference/noInferRestSpread2.ts @@ -0,0 +1,34 @@ +// @strict: true +// @noEmit: true + +// https://github.com/microsoft/TypeScript/issues/63627 + +function arr1(a: [number, ...NoInfer<[]>]) {} +arr1([1]); + +function arr2(a: [number, ...[]]) {} +arr2([1]); + +function fun1(a: (x: number, ...o: NoInfer<[]>) => void) {} +fun1(x => {}); + +function fun2(a: (x: number, ...o: []) => void) {} +fun2(x => {}); + +function func1( + args: A, + fn: (x: number, ...args: NoInfer) => void, +) {} + +func1([] as const, x => {}); + +function func2( + args: A, + fn: (...args: NoInfer) => void, +) {} + +function foo(u: number, v: number) { + func2([u, v] as const, () => {}); + func2([u, v] as const, (x: number) => {}); + func2([u, v] as const, (x: number, y: number) => {}); +}