diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index bcd8ef1771440..f14b91732c2f8 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -1298,6 +1298,12 @@ export const enum SignatureCheckMode { Callback = BivariantCallback | StrictCallback, } +const enum TupleStructureComparisonKind { + None = 0, + MatchFixed = 1 << 0, + MatchVariable = 1 << 1, +} + const enum IntersectionState { None = 0, Source = 1 << 0, // Source type is a constituent of an outer intersection @@ -20732,7 +20738,59 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { for (let i = 0; i < paramCount; i++) { const sourceType = i === restIndex ? getRestOrAnyTypeAtPosition(source, i) : tryGetTypeAtPosition(source, i); - const targetType = i === restIndex ? getRestOrAnyTypeAtPosition(target, i) : tryGetTypeAtPosition(target, i); + let targetType = i === restIndex ? getRestOrAnyTypeAtPosition(target, i) : tryGetTypeAtPosition(target, i); + if (i === restIndex && targetType && sourceType && isTupleType(sourceType)) { + targetType = mapType(targetType, t => { + if ( + !isTupleType(t) || + // When both sides are tuples of the same structure, we don't want to "propagate" types from elements of variable positions + // to the following positions as that would disallow signatures of the exact same structures when trailing fixed elements are involved: + // + // let fn: (...rest: [...string[], number]) => void = (...rest: [...string[], number]) => {}; // ok + // + // Since we want to allow contextual types to flow into paremeters, we don't need to differentiate between rest and variadic elements + // as that doesn't affect the contextual type of the parameter + isTupleTypeStructureMatching(sourceType, t, TupleStructureComparisonKind.MatchVariable) + ) { + return t; + } + + // We create a tuple type based on the target elements and the source's length here. + // When the source signature accepts less parameters than the target signature + // we only need to check the *used* elements of the target tuple, the rest is ignored by the source anyway + // and thus it can be safely ignored here. + // + // let fn: (a: number, b: string) => void = (a: number) => {}; // ok + // + // In addition to that we also want to "propagate" element types of variable positions + // to all following positions, as that represents possible argument types. + // + // function fn(...[a, b]: [...number[], string]) { + // a; // number | string + // b; // number | string + // } + // fn('str'); // valid + const elementTypes: Type[] = []; + const elementFlags: ElementFlags[] = []; + + const sourceArity = getTypeReferenceArity(sourceType); + const targetArity = getTypeReferenceArity(t); + + for (let i = 0; i < sourceArity; i++) { + if (i >= targetArity) { + if (sourceType.target.elementFlags[i] & ElementFlags.Fixed) { + elementTypes.push(undefinedType); + elementFlags.push(sourceType.target.elementFlags[i]); + } + continue; + } + elementTypes.push(getTupleElementType(t, i)!); + elementFlags.push(sourceType.target.elementFlags[i]); + } + + return createTupleType(elementTypes, elementFlags); + }); + } if (sourceType && targetType) { // In order to ensure that any generic type Foo is at least co-variant with respect to T no matter // how Foo uses T, we need to relate parameters bi-variantly (given that parameters are input positions, @@ -24440,9 +24498,14 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return undefined; } - function isTupleTypeStructureMatching(t1: TupleTypeReference, t2: TupleTypeReference) { + function isTupleTypeStructureMatching(t1: TupleTypeReference, t2: TupleTypeReference, tupleStructureComparisonKind: TupleStructureComparisonKind) { return getTypeReferenceArity(t1) === getTypeReferenceArity(t2) && - every(t1.target.elementFlags, (f, i) => (f & ElementFlags.Variable) === (t2.target.elementFlags[i] & ElementFlags.Variable)); + every(t1.target.elementFlags, (f1, i) => { + const f2 = t2.target.elementFlags[i]; + return f1 === f2 || + !!(tupleStructureComparisonKind & TupleStructureComparisonKind.MatchFixed && f1 & ElementFlags.Fixed && f2 & ElementFlags.Fixed) || + !!(tupleStructureComparisonKind & TupleStructureComparisonKind.MatchVariable && f1 & ElementFlags.Variable && f2 & ElementFlags.Variable); + }); } function isZeroBigInt({ value }: BigIntLiteralType) { @@ -26050,7 +26113,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const elementFlags = target.target.elementFlags; // When source and target are tuple types with the same structure (fixed, variadic, and rest are matched // to the same kind in each position), simply infer between the element types. - if (isTupleType(source) && isTupleTypeStructureMatching(source, target)) { + if (isTupleType(source) && isTupleTypeStructureMatching(source, target, TupleStructureComparisonKind.MatchFixed)) { for (let i = 0; i < targetArity; i++) { inferFromTypes(getTypeArguments(source)[i], elementTypes[i]); } diff --git a/tests/baselines/reference/dependentDestructuredVariables.errors.txt b/tests/baselines/reference/dependentDestructuredVariables.errors.txt index f6e2dd3d42745..860bb3faec34b 100644 --- a/tests/baselines/reference/dependentDestructuredVariables.errors.txt +++ b/tests/baselines/reference/dependentDestructuredVariables.errors.txt @@ -402,7 +402,7 @@ dependentDestructuredVariables.ts(431,15): error TS2322: Type 'number' is not as warn: [message: string]; shardDisconnect: [closeEvent: CloseEvent, shardId: number]; } - + declare class Client { public on(event: K, listener: (...args: ClientEvents[K]) => void): void; } @@ -474,4 +474,12 @@ dependentDestructuredVariables.ts(431,15): error TS2322: Type 'number' is not as x; // 1 | 3 } } + + // repros from #47190#issuecomment-1339753554 + const f70: (...args: [type: "one"] | [type: "two", x: string]) => void = (type, x) => { + if (type !== "one") x.toUpperCase(); + } + const f71: (...args: [type: "one", x?: number] | [type: "two", x: string]) => void = (type, x) => { + if (type !== "one") x.toUpperCase(); + } \ No newline at end of file diff --git a/tests/baselines/reference/dependentDestructuredVariables.js b/tests/baselines/reference/dependentDestructuredVariables.js index 7d32808909bf7..a1ba7f9b90a01 100644 --- a/tests/baselines/reference/dependentDestructuredVariables.js +++ b/tests/baselines/reference/dependentDestructuredVariables.js @@ -395,7 +395,7 @@ interface ClientEvents { warn: [message: string]; shardDisconnect: [closeEvent: CloseEvent, shardId: number]; } - + declare class Client { public on(event: K, listener: (...args: ClientEvents[K]) => void): void; } @@ -465,6 +465,14 @@ const parameterReassignedContextualRest1: (...args: [1, 2] | [3, 4]) => void = ( x; // 1 | 3 } } + +// repros from #47190#issuecomment-1339753554 +const f70: (...args: [type: "one"] | [type: "two", x: string]) => void = (type, x) => { + if (type !== "one") x.toUpperCase(); +} +const f71: (...args: [type: "one", x?: number] | [type: "two", x: string]) => void = (type, x) => { + if (type !== "one") x.toUpperCase(); +} //// [dependentDestructuredVariables.js] @@ -823,6 +831,15 @@ const parameterReassignedContextualRest1 = (x, y) => { x; // 1 | 3 } }; +// repros from #47190#issuecomment-1339753554 +const f70 = (type, x) => { + if (type !== "one") + x.toUpperCase(); +}; +const f71 = (type, x) => { + if (type !== "one") + x.toUpperCase(); +}; //// [dependentDestructuredVariables.d.ts] @@ -976,3 +993,5 @@ declare function tooNarrow([x, y]: [1, 1] | [1, 2] | [1]): void; declare function parameterReassigned1([x, y]: [1, 2] | [3, 4]): void; declare function parameterReassigned2([x, y]: [1, 2] | [3, 4]): void; declare const parameterReassignedContextualRest1: (...args: [1, 2] | [3, 4]) => void; +declare const f70: (...args: [type: "one"] | [type: "two", x: string]) => void; +declare const f71: (...args: [type: "one", x?: number] | [type: "two", x: string]) => void; diff --git a/tests/baselines/reference/dependentDestructuredVariables.symbols b/tests/baselines/reference/dependentDestructuredVariables.symbols index ae71b255d1a88..26aed9ed414a9 100644 --- a/tests/baselines/reference/dependentDestructuredVariables.symbols +++ b/tests/baselines/reference/dependentDestructuredVariables.symbols @@ -979,7 +979,7 @@ interface ClientEvents { >shardDisconnect : Symbol(ClientEvents.shardDisconnect, Decl(dependentDestructuredVariables.ts, 391, 28)) >CloseEvent : Symbol(CloseEvent, Decl(lib.dom.d.ts, --, --), Decl(lib.dom.d.ts, --, --)) } - + declare class Client { >Client : Symbol(Client, Decl(dependentDestructuredVariables.ts, 393, 1)) @@ -1168,3 +1168,29 @@ const parameterReassignedContextualRest1: (...args: [1, 2] | [3, 4]) => void = ( } } +// repros from #47190#issuecomment-1339753554 +const f70: (...args: [type: "one"] | [type: "two", x: string]) => void = (type, x) => { +>f70 : Symbol(f70, Decl(dependentDestructuredVariables.ts, 466, 5)) +>args : Symbol(args, Decl(dependentDestructuredVariables.ts, 466, 12)) +>type : Symbol(type, Decl(dependentDestructuredVariables.ts, 466, 74)) +>x : Symbol(x, Decl(dependentDestructuredVariables.ts, 466, 79)) + + if (type !== "one") x.toUpperCase(); +>type : Symbol(type, Decl(dependentDestructuredVariables.ts, 466, 74)) +>x.toUpperCase : Symbol(String.toUpperCase, Decl(lib.es5.d.ts, --, --)) +>x : Symbol(x, Decl(dependentDestructuredVariables.ts, 466, 79)) +>toUpperCase : Symbol(String.toUpperCase, Decl(lib.es5.d.ts, --, --)) +} +const f71: (...args: [type: "one", x?: number] | [type: "two", x: string]) => void = (type, x) => { +>f71 : Symbol(f71, Decl(dependentDestructuredVariables.ts, 469, 5)) +>args : Symbol(args, Decl(dependentDestructuredVariables.ts, 469, 12)) +>type : Symbol(type, Decl(dependentDestructuredVariables.ts, 469, 86)) +>x : Symbol(x, Decl(dependentDestructuredVariables.ts, 469, 91)) + + if (type !== "one") x.toUpperCase(); +>type : Symbol(type, Decl(dependentDestructuredVariables.ts, 469, 86)) +>x.toUpperCase : Symbol(String.toUpperCase, Decl(lib.es5.d.ts, --, --)) +>x : Symbol(x, Decl(dependentDestructuredVariables.ts, 469, 91)) +>toUpperCase : Symbol(String.toUpperCase, Decl(lib.es5.d.ts, --, --)) +} + diff --git a/tests/baselines/reference/dependentDestructuredVariables.types b/tests/baselines/reference/dependentDestructuredVariables.types index 2c9d385bebe84..796c440028075 100644 --- a/tests/baselines/reference/dependentDestructuredVariables.types +++ b/tests/baselines/reference/dependentDestructuredVariables.types @@ -2,7 +2,7 @@ === Performance Stats === Type Count: 2,500 -Instantiation count: 1,000 +Instantiation count: 1,000 -> 2,500 === dependentDestructuredVariables.ts === type Action = @@ -1713,7 +1713,7 @@ interface ClientEvents { >shardDisconnect : [closeEvent: CloseEvent, shardId: number] > : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ } - + declare class Client { >Client : Client > : ^^^^^^ @@ -2067,3 +2067,61 @@ const parameterReassignedContextualRest1: (...args: [1, 2] | [3, 4]) => void = ( } } +// repros from #47190#issuecomment-1339753554 +const f70: (...args: [type: "one"] | [type: "two", x: string]) => void = (type, x) => { +>f70 : (...args: [type: "one"] | [type: "two", x: string]) => void +> : ^^^^ ^^ ^^^^^ +>args : [type: "one"] | [type: "two", x: string] +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>(type, x) => { if (type !== "one") x.toUpperCase();} : (type: "one" | "two", x: string | undefined) => void +> : ^ ^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>type : "one" | "two" +> : ^^^^^^^^^^^^^ +>x : string | undefined +> : ^^^^^^^^^^^^^^^^^^ + + if (type !== "one") x.toUpperCase(); +>type !== "one" : boolean +> : ^^^^^^^ +>type : "one" | "two" +> : ^^^^^^^^^^^^^ +>"one" : "one" +> : ^^^^^ +>x.toUpperCase() : string +> : ^^^^^^ +>x.toUpperCase : () => string +> : ^^^^^^^^^^^^ +>x : string +> : ^^^^^^ +>toUpperCase : () => string +> : ^^^^^^^^^^^^ +} +const f71: (...args: [type: "one", x?: number] | [type: "two", x: string]) => void = (type, x) => { +>f71 : (...args: [type: "one", x?: number] | [type: "two", x: string]) => void +> : ^^^^ ^^ ^^^^^ +>args : [type: "one", x?: number | undefined] | [type: "two", x: string] +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>(type, x) => { if (type !== "one") x.toUpperCase();} : (type: "one" | "two", x: string | number | undefined) => void +> : ^ ^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>type : "one" | "two" +> : ^^^^^^^^^^^^^ +>x : string | number | undefined +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + if (type !== "one") x.toUpperCase(); +>type !== "one" : boolean +> : ^^^^^^^ +>type : "one" | "two" +> : ^^^^^^^^^^^^^ +>"one" : "one" +> : ^^^^^ +>x.toUpperCase() : string +> : ^^^^^^ +>x.toUpperCase : () => string +> : ^^^^^^^^^^^^ +>x : string +> : ^^^^^^ +>toUpperCase : () => string +> : ^^^^^^^^^^^^ +} + diff --git a/tests/baselines/reference/genericRestParameters3.errors.txt b/tests/baselines/reference/genericRestParameters3.errors.txt index 5e072df85e9ce..7025627770363 100644 --- a/tests/baselines/reference/genericRestParameters3.errors.txt +++ b/tests/baselines/reference/genericRestParameters3.errors.txt @@ -6,14 +6,15 @@ genericRestParameters3.ts(18,1): error TS2345: Argument of type '[]' is not assi Source has 0 element(s) but target requires 2. genericRestParameters3.ts(23,1): error TS2322: Type '(x: string, y: string) => void' is not assignable to type '(x: string, ...args: [string] | [number, boolean]) => void'. Types of parameters 'y' and 'args' are incompatible. - Type '[string] | [number, boolean]' is not assignable to type '[y: string]'. - Type '[number, boolean]' is not assignable to type '[y: string]'. - Source has 2 element(s) but target allows only 1. + Type '[string] | [number]' is not assignable to type '[y: string]'. + Type '[number]' is not assignable to type '[y: string]'. + Type 'number' is not assignable to type 'string'. genericRestParameters3.ts(24,1): error TS2322: Type '(x: string, y: number, z: boolean) => void' is not assignable to type '(x: string, ...args: [string] | [number, boolean]) => void'. Types of parameters 'y' and 'args' are incompatible. - Type '[string] | [number, boolean]' is not assignable to type '[y: number, z: boolean]'. - Type '[string]' is not assignable to type '[y: number, z: boolean]'. - Source has 1 element(s) but target requires 2. + Type '[number, boolean] | [string, undefined]' is not assignable to type '[y: number, z: boolean]'. + Type '[string, undefined]' is not assignable to type '[y: number, z: boolean]'. + Type at position 0 in source is not compatible with type at position 0 in target. + Type 'string' is not assignable to type 'number'. genericRestParameters3.ts(35,1): error TS2554: Expected 1 arguments, but got 0. genericRestParameters3.ts(36,21): error TS2345: Argument of type 'number' is not assignable to parameter of type '(...args: CoolArray) => void'. genericRestParameters3.ts(37,21): error TS2345: Argument of type '(cb: (...args: T) => void) => void' is not assignable to parameter of type '(...args: CoolArray) => void'. @@ -69,16 +70,17 @@ genericRestParameters3.ts(59,5): error TS2345: Argument of type '["what"]' is no ~~ !!! error TS2322: Type '(x: string, y: string) => void' is not assignable to type '(x: string, ...args: [string] | [number, boolean]) => void'. !!! error TS2322: Types of parameters 'y' and 'args' are incompatible. -!!! error TS2322: Type '[string] | [number, boolean]' is not assignable to type '[y: string]'. -!!! error TS2322: Type '[number, boolean]' is not assignable to type '[y: string]'. -!!! error TS2322: Source has 2 element(s) but target allows only 1. +!!! error TS2322: Type '[string] | [number]' is not assignable to type '[y: string]'. +!!! error TS2322: Type '[number]' is not assignable to type '[y: string]'. +!!! error TS2322: Type 'number' is not assignable to type 'string'. f1 = f3; // Error ~~ !!! error TS2322: Type '(x: string, y: number, z: boolean) => void' is not assignable to type '(x: string, ...args: [string] | [number, boolean]) => void'. !!! error TS2322: Types of parameters 'y' and 'args' are incompatible. -!!! error TS2322: Type '[string] | [number, boolean]' is not assignable to type '[y: number, z: boolean]'. -!!! error TS2322: Type '[string]' is not assignable to type '[y: number, z: boolean]'. -!!! error TS2322: Source has 1 element(s) but target requires 2. +!!! error TS2322: Type '[number, boolean] | [string, undefined]' is not assignable to type '[y: number, z: boolean]'. +!!! error TS2322: Type '[string, undefined]' is not assignable to type '[y: number, z: boolean]'. +!!! error TS2322: Type at position 0 in source is not compatible with type at position 0 in target. +!!! error TS2322: Type 'string' is not assignable to type 'number'. f1 = f4; // Repro from #26110 diff --git a/tests/baselines/reference/restTupleUnionShorterContextualParams.symbols b/tests/baselines/reference/restTupleUnionShorterContextualParams.symbols new file mode 100644 index 0000000000000..4a3532373bee1 --- /dev/null +++ b/tests/baselines/reference/restTupleUnionShorterContextualParams.symbols @@ -0,0 +1,33 @@ +//// [tests/cases/compiler/restTupleUnionShorterContextualParams.ts] //// + +=== restTupleUnionShorterContextualParams.ts === +// repro #48663 + +// showcase how those transitive assignments are OK +const f1: (x: string | number) => void = x => {}; +>f1 : Symbol(f1, Decl(restTupleUnionShorterContextualParams.ts, 3, 5)) +>x : Symbol(x, Decl(restTupleUnionShorterContextualParams.ts, 3, 11)) +>x : Symbol(x, Decl(restTupleUnionShorterContextualParams.ts, 3, 40)) + +const f2: (x: string | number, y: string | number) => void = f1; +>f2 : Symbol(f2, Decl(restTupleUnionShorterContextualParams.ts, 4, 5)) +>x : Symbol(x, Decl(restTupleUnionShorterContextualParams.ts, 4, 11)) +>y : Symbol(y, Decl(restTupleUnionShorterContextualParams.ts, 4, 30)) +>f1 : Symbol(f1, Decl(restTupleUnionShorterContextualParams.ts, 3, 5)) + +const f3: (...args: [number, string] | [string, number]) => void = f2; +>f3 : Symbol(f3, Decl(restTupleUnionShorterContextualParams.ts, 5, 5)) +>args : Symbol(args, Decl(restTupleUnionShorterContextualParams.ts, 5, 11)) +>f2 : Symbol(f2, Decl(restTupleUnionShorterContextualParams.ts, 4, 5)) + +// by extension those should be OK too +const f4: (...args: [number, string] | [string, number]) => void = (item) => {} +>f4 : Symbol(f4, Decl(restTupleUnionShorterContextualParams.ts, 8, 5)) +>args : Symbol(args, Decl(restTupleUnionShorterContextualParams.ts, 8, 11)) +>item : Symbol(item, Decl(restTupleUnionShorterContextualParams.ts, 8, 68)) + +const f5: (...args: [number, string] | [string, number]) => void = (item: number | string) => {} +>f5 : Symbol(f5, Decl(restTupleUnionShorterContextualParams.ts, 9, 5)) +>args : Symbol(args, Decl(restTupleUnionShorterContextualParams.ts, 9, 11)) +>item : Symbol(item, Decl(restTupleUnionShorterContextualParams.ts, 9, 68)) + diff --git a/tests/baselines/reference/restTupleUnionShorterContextualParams.types b/tests/baselines/reference/restTupleUnionShorterContextualParams.types new file mode 100644 index 0000000000000..617c52a604e46 --- /dev/null +++ b/tests/baselines/reference/restTupleUnionShorterContextualParams.types @@ -0,0 +1,55 @@ +//// [tests/cases/compiler/restTupleUnionShorterContextualParams.ts] //// + +=== restTupleUnionShorterContextualParams.ts === +// repro #48663 + +// showcase how those transitive assignments are OK +const f1: (x: string | number) => void = x => {}; +>f1 : (x: string | number) => void +> : ^ ^^ ^^^^^ +>x : string | number +> : ^^^^^^^^^^^^^^^ +>x => {} : (x: string | number) => void +> : ^ ^^^^^^^^^^^^^^^^^^^^^^^^^^ +>x : string | number +> : ^^^^^^^^^^^^^^^ + +const f2: (x: string | number, y: string | number) => void = f1; +>f2 : (x: string | number, y: string | number) => void +> : ^ ^^ ^^ ^^ ^^^^^ +>x : string | number +> : ^^^^^^^^^^^^^^^ +>y : string | number +> : ^^^^^^^^^^^^^^^ +>f1 : (x: string | number) => void +> : ^ ^^ ^^^^^^^^^ + +const f3: (...args: [number, string] | [string, number]) => void = f2; +>f3 : (...args: [number, string] | [string, number]) => void +> : ^^^^ ^^ ^^^^^ +>args : [number, string] | [string, number] +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>f2 : (x: string | number, y: string | number) => void +> : ^ ^^ ^^ ^^ ^^^^^^^^^ + +// by extension those should be OK too +const f4: (...args: [number, string] | [string, number]) => void = (item) => {} +>f4 : (...args: [number, string] | [string, number]) => void +> : ^^^^ ^^ ^^^^^ +>args : [number, string] | [string, number] +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>(item) => {} : (item: string | number) => void +> : ^ ^^^^^^^^^^^^^^^^^^^^^^^^^^ +>item : string | number +> : ^^^^^^^^^^^^^^^ + +const f5: (...args: [number, string] | [string, number]) => void = (item: number | string) => {} +>f5 : (...args: [number, string] | [string, number]) => void +> : ^^^^ ^^ ^^^^^ +>args : [number, string] | [string, number] +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>(item: number | string) => {} : (item: number | string) => void +> : ^ ^^ ^^^^^^^^^ +>item : string | number +> : ^^^^^^^^^^^^^^^ + diff --git a/tests/baselines/reference/restTupleUnionWithRestContextualParams.symbols b/tests/baselines/reference/restTupleUnionWithRestContextualParams.symbols new file mode 100644 index 0000000000000..76009ec9c8e8c --- /dev/null +++ b/tests/baselines/reference/restTupleUnionWithRestContextualParams.symbols @@ -0,0 +1,212 @@ +//// [tests/cases/compiler/restTupleUnionWithRestContextualParams.ts] //// + +=== restTupleUnionWithRestContextualParams.ts === +const f1: (...args: [number, string, ...boolean[]] | [string, number, ...boolean[]]) => void = (a, b, c) => {}; +>f1 : Symbol(f1, Decl(restTupleUnionWithRestContextualParams.ts, 0, 5)) +>args : Symbol(args, Decl(restTupleUnionWithRestContextualParams.ts, 0, 11)) +>a : Symbol(a, Decl(restTupleUnionWithRestContextualParams.ts, 0, 96)) +>b : Symbol(b, Decl(restTupleUnionWithRestContextualParams.ts, 0, 98)) +>c : Symbol(c, Decl(restTupleUnionWithRestContextualParams.ts, 0, 101)) + +const f2: (x: string, ...args: [string] | [number, boolean]) => void = (a, b, c) => {}; +>f2 : Symbol(f2, Decl(restTupleUnionWithRestContextualParams.ts, 2, 5)) +>x : Symbol(x, Decl(restTupleUnionWithRestContextualParams.ts, 2, 11)) +>args : Symbol(args, Decl(restTupleUnionWithRestContextualParams.ts, 2, 21)) +>a : Symbol(a, Decl(restTupleUnionWithRestContextualParams.ts, 2, 72)) +>b : Symbol(b, Decl(restTupleUnionWithRestContextualParams.ts, 2, 74)) +>c : Symbol(c, Decl(restTupleUnionWithRestContextualParams.ts, 2, 77)) + +const f3: (...args: [type: "one"] | [type: "two", x: string]) => void = (type, x) => {} +>f3 : Symbol(f3, Decl(restTupleUnionWithRestContextualParams.ts, 4, 5)) +>args : Symbol(args, Decl(restTupleUnionWithRestContextualParams.ts, 4, 11)) +>type : Symbol(type, Decl(restTupleUnionWithRestContextualParams.ts, 4, 73)) +>x : Symbol(x, Decl(restTupleUnionWithRestContextualParams.ts, 4, 78)) + +const f4: (...args: [type: "one", x?: number] | [type: "two", x: string]) => void = (type, x) => {} +>f4 : Symbol(f4, Decl(restTupleUnionWithRestContextualParams.ts, 6, 5)) +>args : Symbol(args, Decl(restTupleUnionWithRestContextualParams.ts, 6, 11)) +>type : Symbol(type, Decl(restTupleUnionWithRestContextualParams.ts, 6, 85)) +>x : Symbol(x, Decl(restTupleUnionWithRestContextualParams.ts, 6, 90)) + +// #45972 +type Fn1 = (...args: [...strs: string[], num1: number, num2: number]) => void; +>Fn1 : Symbol(Fn1, Decl(restTupleUnionWithRestContextualParams.ts, 6, 99)) +>args : Symbol(args, Decl(restTupleUnionWithRestContextualParams.ts, 9, 12)) + +const f5: Fn1 = () => {} +>f5 : Symbol(f5, Decl(restTupleUnionWithRestContextualParams.ts, 10, 5)) +>Fn1 : Symbol(Fn1, Decl(restTupleUnionWithRestContextualParams.ts, 6, 99)) + +const f6: Fn1 = (arg1) => {} +>f6 : Symbol(f6, Decl(restTupleUnionWithRestContextualParams.ts, 11, 5)) +>Fn1 : Symbol(Fn1, Decl(restTupleUnionWithRestContextualParams.ts, 6, 99)) +>arg1 : Symbol(arg1, Decl(restTupleUnionWithRestContextualParams.ts, 11, 17)) + +const f7: Fn1 = (arg1, arg2) => {} +>f7 : Symbol(f7, Decl(restTupleUnionWithRestContextualParams.ts, 12, 5)) +>Fn1 : Symbol(Fn1, Decl(restTupleUnionWithRestContextualParams.ts, 6, 99)) +>arg1 : Symbol(arg1, Decl(restTupleUnionWithRestContextualParams.ts, 12, 17)) +>arg2 : Symbol(arg2, Decl(restTupleUnionWithRestContextualParams.ts, 12, 22)) + +const f8: Fn1 = (arg1, arg2, arg3) => {} +>f8 : Symbol(f8, Decl(restTupleUnionWithRestContextualParams.ts, 13, 5)) +>Fn1 : Symbol(Fn1, Decl(restTupleUnionWithRestContextualParams.ts, 6, 99)) +>arg1 : Symbol(arg1, Decl(restTupleUnionWithRestContextualParams.ts, 13, 17)) +>arg2 : Symbol(arg2, Decl(restTupleUnionWithRestContextualParams.ts, 13, 22)) +>arg3 : Symbol(arg3, Decl(restTupleUnionWithRestContextualParams.ts, 13, 28)) + +// #45972#issuecomment-1140417029 +const f9: Fn1 = (...[arg1]: [string | number]) => {} +>f9 : Symbol(f9, Decl(restTupleUnionWithRestContextualParams.ts, 16, 5)) +>Fn1 : Symbol(Fn1, Decl(restTupleUnionWithRestContextualParams.ts, 6, 99)) +>arg1 : Symbol(arg1, Decl(restTupleUnionWithRestContextualParams.ts, 16, 21)) + +const f10: Fn1 = (...[arg1, arg2]: [string | number, string | number]) => {} +>f10 : Symbol(f10, Decl(restTupleUnionWithRestContextualParams.ts, 17, 5)) +>Fn1 : Symbol(Fn1, Decl(restTupleUnionWithRestContextualParams.ts, 6, 99)) +>arg1 : Symbol(arg1, Decl(restTupleUnionWithRestContextualParams.ts, 17, 22)) +>arg2 : Symbol(arg2, Decl(restTupleUnionWithRestContextualParams.ts, 17, 27)) + +const f11: Fn1 = (...[arg1, arg2, arg3]: [string | number, string | number, string | number]) => {} +>f11 : Symbol(f11, Decl(restTupleUnionWithRestContextualParams.ts, 18, 5)) +>Fn1 : Symbol(Fn1, Decl(restTupleUnionWithRestContextualParams.ts, 6, 99)) +>arg1 : Symbol(arg1, Decl(restTupleUnionWithRestContextualParams.ts, 18, 22)) +>arg2 : Symbol(arg2, Decl(restTupleUnionWithRestContextualParams.ts, 18, 27)) +>arg3 : Symbol(arg3, Decl(restTupleUnionWithRestContextualParams.ts, 18, 33)) + +const f12: (...args: [...strs: string[], num: number]) => void = (a, ...rest) => {} +>f12 : Symbol(f12, Decl(restTupleUnionWithRestContextualParams.ts, 20, 5)) +>args : Symbol(args, Decl(restTupleUnionWithRestContextualParams.ts, 20, 12)) +>a : Symbol(a, Decl(restTupleUnionWithRestContextualParams.ts, 20, 66)) +>rest : Symbol(rest, Decl(restTupleUnionWithRestContextualParams.ts, 20, 68)) + +// #49218#pullrequestreview-1241473951 +const f13: (...rest: [number, ...T, boolean] ) => void = (a: number, ...arg: [...string[], boolean]) => {}; +>f13 : Symbol(f13, Decl(restTupleUnionWithRestContextualParams.ts, 23, 5)) +>T : Symbol(T, Decl(restTupleUnionWithRestContextualParams.ts, 23, 12)) +>rest : Symbol(rest, Decl(restTupleUnionWithRestContextualParams.ts, 23, 32)) +>T : Symbol(T, Decl(restTupleUnionWithRestContextualParams.ts, 23, 12)) +>a : Symbol(a, Decl(restTupleUnionWithRestContextualParams.ts, 23, 78)) +>arg : Symbol(arg, Decl(restTupleUnionWithRestContextualParams.ts, 23, 88)) + +const f14: (...rest: [number, ...string[], T] ) => void = (a: number, ...arg: [...string[], boolean]) => {}; +>f14 : Symbol(f14, Decl(restTupleUnionWithRestContextualParams.ts, 25, 5)) +>T : Symbol(T, Decl(restTupleUnionWithRestContextualParams.ts, 25, 12)) +>rest : Symbol(rest, Decl(restTupleUnionWithRestContextualParams.ts, 25, 31)) +>T : Symbol(T, Decl(restTupleUnionWithRestContextualParams.ts, 25, 12)) +>a : Symbol(a, Decl(restTupleUnionWithRestContextualParams.ts, 25, 78)) +>arg : Symbol(arg, Decl(restTupleUnionWithRestContextualParams.ts, 25, 88)) + +const f15: (...rest: [number, ...T[], boolean] ) => void = (a: number, ...arg: [...string[], boolean]) => {}; +>f15 : Symbol(f15, Decl(restTupleUnionWithRestContextualParams.ts, 26, 5)) +>T : Symbol(T, Decl(restTupleUnionWithRestContextualParams.ts, 26, 12)) +>rest : Symbol(rest, Decl(restTupleUnionWithRestContextualParams.ts, 26, 30)) +>T : Symbol(T, Decl(restTupleUnionWithRestContextualParams.ts, 26, 12)) +>a : Symbol(a, Decl(restTupleUnionWithRestContextualParams.ts, 26, 78)) +>arg : Symbol(arg, Decl(restTupleUnionWithRestContextualParams.ts, 26, 88)) + +const f16: (...rest: [...string[], number]) => void = (...rest: [...string[], number]) => {}; +>f16 : Symbol(f16, Decl(restTupleUnionWithRestContextualParams.ts, 28, 5)) +>rest : Symbol(rest, Decl(restTupleUnionWithRestContextualParams.ts, 28, 12)) +>rest : Symbol(rest, Decl(restTupleUnionWithRestContextualParams.ts, 28, 55)) + +const f17: (...rest: [...string[], number]) => void = (a, b, c?) => {}; +>f17 : Symbol(f17, Decl(restTupleUnionWithRestContextualParams.ts, 30, 5)) +>rest : Symbol(rest, Decl(restTupleUnionWithRestContextualParams.ts, 30, 12)) +>a : Symbol(a, Decl(restTupleUnionWithRestContextualParams.ts, 30, 55)) +>b : Symbol(b, Decl(restTupleUnionWithRestContextualParams.ts, 30, 57)) +>c : Symbol(c, Decl(restTupleUnionWithRestContextualParams.ts, 30, 60)) + +const f18: (...rest: [...string[], number]) => void = (a, b, c?: string | number) => {}; +>f18 : Symbol(f18, Decl(restTupleUnionWithRestContextualParams.ts, 31, 5)) +>rest : Symbol(rest, Decl(restTupleUnionWithRestContextualParams.ts, 31, 12)) +>a : Symbol(a, Decl(restTupleUnionWithRestContextualParams.ts, 31, 55)) +>b : Symbol(b, Decl(restTupleUnionWithRestContextualParams.ts, 31, 57)) +>c : Symbol(c, Decl(restTupleUnionWithRestContextualParams.ts, 31, 60)) + +const f19: (...rest: [string, ...boolean[], string] | [number]) => void = (a, ...rest) => {}; +>f19 : Symbol(f19, Decl(restTupleUnionWithRestContextualParams.ts, 33, 5)) +>rest : Symbol(rest, Decl(restTupleUnionWithRestContextualParams.ts, 33, 12)) +>a : Symbol(a, Decl(restTupleUnionWithRestContextualParams.ts, 33, 75)) +>rest : Symbol(rest, Decl(restTupleUnionWithRestContextualParams.ts, 33, 77)) + +type entryArgsWithIndex = { +>entryArgsWithIndex : Symbol(entryArgsWithIndex, Decl(restTupleUnionWithRestContextualParams.ts, 33, 93)) +>o : Symbol(o, Decl(restTupleUnionWithRestContextualParams.ts, 35, 24)) + + [k in keyof o]: [k: k, v: o[k], i: number]; +>k : Symbol(k, Decl(restTupleUnionWithRestContextualParams.ts, 36, 3)) +>o : Symbol(o, Decl(restTupleUnionWithRestContextualParams.ts, 35, 24)) +>k : Symbol(k, Decl(restTupleUnionWithRestContextualParams.ts, 36, 3)) +>o : Symbol(o, Decl(restTupleUnionWithRestContextualParams.ts, 35, 24)) +>k : Symbol(k, Decl(restTupleUnionWithRestContextualParams.ts, 36, 3)) + +}[keyof o]; +>o : Symbol(o, Decl(restTupleUnionWithRestContextualParams.ts, 35, 24)) + +declare const iterateEntries1: ( +>iterateEntries1 : Symbol(iterateEntries1, Decl(restTupleUnionWithRestContextualParams.ts, 39, 13)) +>o : Symbol(o, Decl(restTupleUnionWithRestContextualParams.ts, 39, 32), Decl(restTupleUnionWithRestContextualParams.ts, 39, 56)) + + o: o, +>o : Symbol(o, Decl(restTupleUnionWithRestContextualParams.ts, 39, 32), Decl(restTupleUnionWithRestContextualParams.ts, 39, 56)) +>o : Symbol(o, Decl(restTupleUnionWithRestContextualParams.ts, 39, 32), Decl(restTupleUnionWithRestContextualParams.ts, 39, 56)) + + flatMapEntry: (...args: entryArgsWithIndex) => void, +>flatMapEntry : Symbol(flatMapEntry, Decl(restTupleUnionWithRestContextualParams.ts, 40, 7)) +>args : Symbol(args, Decl(restTupleUnionWithRestContextualParams.ts, 41, 17)) +>entryArgsWithIndex : Symbol(entryArgsWithIndex, Decl(restTupleUnionWithRestContextualParams.ts, 33, 93)) +>o : Symbol(o, Decl(restTupleUnionWithRestContextualParams.ts, 39, 32), Decl(restTupleUnionWithRestContextualParams.ts, 39, 56)) + +) => void; + +const ie1 = iterateEntries1({ a: true, b: false }, (k, v) => [k, v]); +>ie1 : Symbol(ie1, Decl(restTupleUnionWithRestContextualParams.ts, 44, 5)) +>iterateEntries1 : Symbol(iterateEntries1, Decl(restTupleUnionWithRestContextualParams.ts, 39, 13)) +>a : Symbol(a, Decl(restTupleUnionWithRestContextualParams.ts, 44, 29)) +>b : Symbol(b, Decl(restTupleUnionWithRestContextualParams.ts, 44, 38)) +>k : Symbol(k, Decl(restTupleUnionWithRestContextualParams.ts, 44, 52)) +>v : Symbol(v, Decl(restTupleUnionWithRestContextualParams.ts, 44, 54)) +>k : Symbol(k, Decl(restTupleUnionWithRestContextualParams.ts, 44, 52)) +>v : Symbol(v, Decl(restTupleUnionWithRestContextualParams.ts, 44, 54)) + +const ie2 = iterateEntries1({ a: true, b: false }, (k, v) => { +>ie2 : Symbol(ie2, Decl(restTupleUnionWithRestContextualParams.ts, 45, 5)) +>iterateEntries1 : Symbol(iterateEntries1, Decl(restTupleUnionWithRestContextualParams.ts, 39, 13)) +>a : Symbol(a, Decl(restTupleUnionWithRestContextualParams.ts, 45, 29)) +>b : Symbol(b, Decl(restTupleUnionWithRestContextualParams.ts, 45, 38)) +>k : Symbol(k, Decl(restTupleUnionWithRestContextualParams.ts, 45, 52)) +>v : Symbol(v, Decl(restTupleUnionWithRestContextualParams.ts, 45, 54)) + + return [k, v]; +>k : Symbol(k, Decl(restTupleUnionWithRestContextualParams.ts, 45, 52)) +>v : Symbol(v, Decl(restTupleUnionWithRestContextualParams.ts, 45, 54)) + +}); + +declare const iterateEntries2: ( +>iterateEntries2 : Symbol(iterateEntries2, Decl(restTupleUnionWithRestContextualParams.ts, 49, 13)) +>o : Symbol(o, Decl(restTupleUnionWithRestContextualParams.ts, 49, 32), Decl(restTupleUnionWithRestContextualParams.ts, 49, 56)) + + o: o, +>o : Symbol(o, Decl(restTupleUnionWithRestContextualParams.ts, 49, 32), Decl(restTupleUnionWithRestContextualParams.ts, 49, 56)) +>o : Symbol(o, Decl(restTupleUnionWithRestContextualParams.ts, 49, 32), Decl(restTupleUnionWithRestContextualParams.ts, 49, 56)) + + flatMapEntry: (...args: entryArgsWithIndex) => unknown, +>flatMapEntry : Symbol(flatMapEntry, Decl(restTupleUnionWithRestContextualParams.ts, 50, 7)) +>args : Symbol(args, Decl(restTupleUnionWithRestContextualParams.ts, 51, 17)) +>entryArgsWithIndex : Symbol(entryArgsWithIndex, Decl(restTupleUnionWithRestContextualParams.ts, 33, 93)) +>o : Symbol(o, Decl(restTupleUnionWithRestContextualParams.ts, 49, 32), Decl(restTupleUnionWithRestContextualParams.ts, 49, 56)) + +) => void; + +const ie3 = iterateEntries2({ a: true, b: false }, (k, v) => [k, v]); +>ie3 : Symbol(ie3, Decl(restTupleUnionWithRestContextualParams.ts, 54, 5)) +>iterateEntries2 : Symbol(iterateEntries2, Decl(restTupleUnionWithRestContextualParams.ts, 49, 13)) +>a : Symbol(a, Decl(restTupleUnionWithRestContextualParams.ts, 54, 29)) +>b : Symbol(b, Decl(restTupleUnionWithRestContextualParams.ts, 54, 38)) +>k : Symbol(k, Decl(restTupleUnionWithRestContextualParams.ts, 54, 52)) +>v : Symbol(v, Decl(restTupleUnionWithRestContextualParams.ts, 54, 54)) +>k : Symbol(k, Decl(restTupleUnionWithRestContextualParams.ts, 54, 52)) +>v : Symbol(v, Decl(restTupleUnionWithRestContextualParams.ts, 54, 54)) + diff --git a/tests/baselines/reference/restTupleUnionWithRestContextualParams.types b/tests/baselines/reference/restTupleUnionWithRestContextualParams.types new file mode 100644 index 0000000000000..450b35d896371 --- /dev/null +++ b/tests/baselines/reference/restTupleUnionWithRestContextualParams.types @@ -0,0 +1,363 @@ +//// [tests/cases/compiler/restTupleUnionWithRestContextualParams.ts] //// + +=== restTupleUnionWithRestContextualParams.ts === +const f1: (...args: [number, string, ...boolean[]] | [string, number, ...boolean[]]) => void = (a, b, c) => {}; +>f1 : (...args: [number, string, ...boolean[]] | [string, number, ...boolean[]]) => void +> : ^^^^ ^^ ^^^^^ +>args : [number, string, ...boolean[]] | [string, number, ...boolean[]] +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>(a, b, c) => {} : (a: string | number, b: string | number, c: boolean) => void +> : ^ ^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^ +>a : string | number +> : ^^^^^^^^^^^^^^^ +>b : string | number +> : ^^^^^^^^^^^^^^^ +>c : boolean +> : ^^^^^^^ + +const f2: (x: string, ...args: [string] | [number, boolean]) => void = (a, b, c) => {}; +>f2 : (x: string, ...args: [string] | [number, boolean]) => void +> : ^ ^^ ^^^^^ ^^ ^^^^^ +>x : string +> : ^^^^^^ +>args : [string] | [number, boolean] +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>(a, b, c) => {} : (a: string, b: string | number, c: boolean | undefined) => void +> : ^ ^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>a : string +> : ^^^^^^ +>b : string | number +> : ^^^^^^^^^^^^^^^ +>c : boolean | undefined +> : ^^^^^^^^^^^^^^^^^^^ + +const f3: (...args: [type: "one"] | [type: "two", x: string]) => void = (type, x) => {} +>f3 : (...args: [type: "one"] | [type: "two", x: string]) => void +> : ^^^^ ^^ ^^^^^ +>args : [type: "one"] | [type: "two", x: string] +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>(type, x) => {} : (type: "one" | "two", x: string | undefined) => void +> : ^ ^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>type : "one" | "two" +> : ^^^^^^^^^^^^^ +>x : string | undefined +> : ^^^^^^^^^^^^^^^^^^ + +const f4: (...args: [type: "one", x?: number] | [type: "two", x: string]) => void = (type, x) => {} +>f4 : (...args: [type: "one", x?: number] | [type: "two", x: string]) => void +> : ^^^^ ^^ ^^^^^ +>args : [type: "one", x?: number | undefined] | [type: "two", x: string] +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>(type, x) => {} : (type: "one" | "two", x: string | number | undefined) => void +> : ^ ^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>type : "one" | "two" +> : ^^^^^^^^^^^^^ +>x : string | number | undefined +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +// #45972 +type Fn1 = (...args: [...strs: string[], num1: number, num2: number]) => void; +>Fn1 : Fn1 +> : ^^^ +>args : [...strs: string[], num1: number, num2: number] +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +const f5: Fn1 = () => {} +>f5 : Fn1 +> : ^^^ +>() => {} : () => void +> : ^^^^^^^^^^ + +const f6: Fn1 = (arg1) => {} +>f6 : Fn1 +> : ^^^ +>(arg1) => {} : (arg1: string | number) => void +> : ^ ^^^^^^^^^^^^^^^^^^^^^^^^^^ +>arg1 : string | number +> : ^^^^^^^^^^^^^^^ + +const f7: Fn1 = (arg1, arg2) => {} +>f7 : Fn1 +> : ^^^ +>(arg1, arg2) => {} : (arg1: string | number, arg2: string | number) => void +> : ^ ^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^ +>arg1 : string | number +> : ^^^^^^^^^^^^^^^ +>arg2 : string | number +> : ^^^^^^^^^^^^^^^ + +const f8: Fn1 = (arg1, arg2, arg3) => {} +>f8 : Fn1 +> : ^^^ +>(arg1, arg2, arg3) => {} : (arg1: string | number, arg2: string | number, arg3: string | number) => void +> : ^ ^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^ +>arg1 : string | number +> : ^^^^^^^^^^^^^^^ +>arg2 : string | number +> : ^^^^^^^^^^^^^^^ +>arg3 : string | number +> : ^^^^^^^^^^^^^^^ + +// #45972#issuecomment-1140417029 +const f9: Fn1 = (...[arg1]: [string | number]) => {} +>f9 : Fn1 +> : ^^^ +>(...[arg1]: [string | number]) => {} : (__0_0: string | number) => void +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>arg1 : string | number +> : ^^^^^^^^^^^^^^^ + +const f10: Fn1 = (...[arg1, arg2]: [string | number, string | number]) => {} +>f10 : Fn1 +> : ^^^ +>(...[arg1, arg2]: [string | number, string | number]) => {} : (__0_0: string | number, __0_1: string | number) => void +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>arg1 : string | number +> : ^^^^^^^^^^^^^^^ +>arg2 : string | number +> : ^^^^^^^^^^^^^^^ + +const f11: Fn1 = (...[arg1, arg2, arg3]: [string | number, string | number, string | number]) => {} +>f11 : Fn1 +> : ^^^ +>(...[arg1, arg2, arg3]: [string | number, string | number, string | number]) => {} : (__0_0: string | number, __0_1: string | number, __0_2: string | number) => void +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>arg1 : string | number +> : ^^^^^^^^^^^^^^^ +>arg2 : string | number +> : ^^^^^^^^^^^^^^^ +>arg3 : string | number +> : ^^^^^^^^^^^^^^^ + +const f12: (...args: [...strs: string[], num: number]) => void = (a, ...rest) => {} +>f12 : (...args: [...strs: string[], num: number]) => void +> : ^^^^ ^^ ^^^^^ +>args : [...strs: string[], num: number] +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>(a, ...rest) => {} : (a: string | number, ...rest: (string | number)[]) => void +> : ^ ^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>a : string | number +> : ^^^^^^^^^^^^^^^ +>rest : (string | number)[] +> : ^^^^^^^^^^^^^^^^^^^ + +// #49218#pullrequestreview-1241473951 +const f13: (...rest: [number, ...T, boolean] ) => void = (a: number, ...arg: [...string[], boolean]) => {}; +>f13 : (...rest: [number, ...T, boolean]) => void +> : ^ ^^^^^^^^^^^^^^^^^^^^^^ ^^ ^^^^^ +>rest : [number, ...T, boolean] +> : ^^^^^^^^^^^^^^^^^^^^^^^ +>(a: number, ...arg: [...string[], boolean]) => {} : (a: number, ...arg: [...string[], boolean]) => void +> : ^ ^^ ^^^^^ ^^ ^^^^^^^^^ +>a : number +> : ^^^^^^ +>arg : [...string[], boolean] +> : ^^^^^^^^^^^^^^^^^^^^^^ + +const f14: (...rest: [number, ...string[], T] ) => void = (a: number, ...arg: [...string[], boolean]) => {}; +>f14 : (...rest: [number, ...string[], T]) => void +> : ^ ^^^^^^^^^^^^^^^^^^^^^ ^^ ^^^^^ +>rest : [number, ...string[], T] +> : ^^^^^^^^^^^^^^^^^^^^^^^^ +>(a: number, ...arg: [...string[], boolean]) => {} : (a: number, ...arg: [...string[], boolean]) => void +> : ^ ^^ ^^^^^ ^^ ^^^^^^^^^ +>a : number +> : ^^^^^^ +>arg : [...string[], boolean] +> : ^^^^^^^^^^^^^^^^^^^^^^ + +const f15: (...rest: [number, ...T[], boolean] ) => void = (a: number, ...arg: [...string[], boolean]) => {}; +>f15 : (...rest: [number, ...T[], boolean]) => void +> : ^ ^^^^^^^^^^^^^^^^^^^^ ^^ ^^^^^ +>rest : [number, ...T[], boolean] +> : ^^^^^^^^^^^^^^^^^^^^^^^^^ +>(a: number, ...arg: [...string[], boolean]) => {} : (a: number, ...arg: [...string[], boolean]) => void +> : ^ ^^ ^^^^^ ^^ ^^^^^^^^^ +>a : number +> : ^^^^^^ +>arg : [...string[], boolean] +> : ^^^^^^^^^^^^^^^^^^^^^^ + +const f16: (...rest: [...string[], number]) => void = (...rest: [...string[], number]) => {}; +>f16 : (...rest: [...string[], number]) => void +> : ^^^^ ^^ ^^^^^ +>rest : [...string[], number] +> : ^^^^^^^^^^^^^^^^^^^^^ +>(...rest: [...string[], number]) => {} : (...rest: [...string[], number]) => void +> : ^^^^ ^^ ^^^^^^^^^ +>rest : [...string[], number] +> : ^^^^^^^^^^^^^^^^^^^^^ + +const f17: (...rest: [...string[], number]) => void = (a, b, c?) => {}; +>f17 : (...rest: [...string[], number]) => void +> : ^^^^ ^^ ^^^^^ +>rest : [...string[], number] +> : ^^^^^^^^^^^^^^^^^^^^^ +>(a, b, c?) => {} : (a: string | number, b: string | number, c?: string | number | undefined) => void +> : ^ ^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>a : string | number +> : ^^^^^^^^^^^^^^^ +>b : string | number +> : ^^^^^^^^^^^^^^^ +>c : string | number | undefined +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +const f18: (...rest: [...string[], number]) => void = (a, b, c?: string | number) => {}; +>f18 : (...rest: [...string[], number]) => void +> : ^^^^ ^^ ^^^^^ +>rest : [...string[], number] +> : ^^^^^^^^^^^^^^^^^^^^^ +>(a, b, c?: string | number) => {} : (a: string | number, b: string | number, c?: string | number) => void +> : ^ ^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^ ^^^ ^^^^^^^^^ +>a : string | number +> : ^^^^^^^^^^^^^^^ +>b : string | number +> : ^^^^^^^^^^^^^^^ +>c : string | number | undefined +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +const f19: (...rest: [string, ...boolean[], string] | [number]) => void = (a, ...rest) => {}; +>f19 : (...rest: [string, ...boolean[], string] | [number]) => void +> : ^^^^ ^^ ^^^^^ +>rest : [string, ...boolean[], string] | [number] +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>(a, ...rest) => {} : (a: string | number, ...rest: (string | number | boolean)[]) => void +> : ^ ^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>a : string | number +> : ^^^^^^^^^^^^^^^ +>rest : (string | number | boolean)[] +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +type entryArgsWithIndex = { +>entryArgsWithIndex : entryArgsWithIndex +> : ^^^^^^^^^^^^^^^^^^^^^ + + [k in keyof o]: [k: k, v: o[k], i: number]; +}[keyof o]; + +declare const iterateEntries1: ( +>iterateEntries1 : (o: o, flatMapEntry: (...args: entryArgsWithIndex) => void) => void +> : ^^^^^^^ ^^^^^^^^^^^^^^^^^ ^^ ^^ ^^ ^^^^^ + + o: o, +>o : o +> : ^ + + flatMapEntry: (...args: entryArgsWithIndex) => void, +>flatMapEntry : (...args: entryArgsWithIndex) => void +> : ^^^^ ^^ ^^^^^ +>args : entryArgsWithIndex +> : ^^^^^^^^^^^^^^^^^^^^^ + +) => void; + +const ie1 = iterateEntries1({ a: true, b: false }, (k, v) => [k, v]); +>ie1 : void +> : ^^^^ +>iterateEntries1({ a: true, b: false }, (k, v) => [k, v]) : void +> : ^^^^ +>iterateEntries1 : (o: o, flatMapEntry: (...args: entryArgsWithIndex) => void) => void +> : ^^^^^^^ ^^^^^^^^^^^^^^^^^ ^^ ^^ ^^ ^^^^^^^^^ +>{ a: true, b: false } : { a: true; b: false; } +> : ^^^^^^^^^^^^^^^^^^^^^^ +>a : true +> : ^^^^ +>true : true +> : ^^^^ +>b : false +> : ^^^^^ +>false : false +> : ^^^^^ +>(k, v) => [k, v] : (k: "a" | "b", v: boolean) => (boolean | "a" | "b")[] +> : ^ ^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>k : "a" | "b" +> : ^^^^^^^^^ +>v : boolean +> : ^^^^^^^ +>[k, v] : (boolean | "a" | "b")[] +> : ^^^^^^^^^^^^^^^^^^^^^^^ +>k : "a" | "b" +> : ^^^^^^^^^ +>v : boolean +> : ^^^^^^^ + +const ie2 = iterateEntries1({ a: true, b: false }, (k, v) => { +>ie2 : void +> : ^^^^ +>iterateEntries1({ a: true, b: false }, (k, v) => { return [k, v];}) : void +> : ^^^^ +>iterateEntries1 : (o: o, flatMapEntry: (...args: entryArgsWithIndex) => void) => void +> : ^^^^^^^ ^^^^^^^^^^^^^^^^^ ^^ ^^ ^^ ^^^^^^^^^ +>{ a: true, b: false } : { a: true; b: false; } +> : ^^^^^^^^^^^^^^^^^^^^^^ +>a : true +> : ^^^^ +>true : true +> : ^^^^ +>b : false +> : ^^^^^ +>false : false +> : ^^^^^ +>(k, v) => { return [k, v];} : (k: "a" | "b", v: boolean) => (boolean | "a" | "b")[] +> : ^ ^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>k : "a" | "b" +> : ^^^^^^^^^ +>v : boolean +> : ^^^^^^^ + + return [k, v]; +>[k, v] : (boolean | "a" | "b")[] +> : ^^^^^^^^^^^^^^^^^^^^^^^ +>k : "a" | "b" +> : ^^^^^^^^^ +>v : boolean +> : ^^^^^^^ + +}); + +declare const iterateEntries2: ( +>iterateEntries2 : (o: o, flatMapEntry: (...args: entryArgsWithIndex) => unknown) => void +> : ^^^^^^^ ^^^^^^^^^^^^^^^^^ ^^ ^^ ^^ ^^^^^ + + o: o, +>o : o +> : ^ + + flatMapEntry: (...args: entryArgsWithIndex) => unknown, +>flatMapEntry : (...args: entryArgsWithIndex) => unknown +> : ^^^^ ^^ ^^^^^ +>args : entryArgsWithIndex +> : ^^^^^^^^^^^^^^^^^^^^^ + +) => void; + +const ie3 = iterateEntries2({ a: true, b: false }, (k, v) => [k, v]); +>ie3 : void +> : ^^^^ +>iterateEntries2({ a: true, b: false }, (k, v) => [k, v]) : void +> : ^^^^ +>iterateEntries2 : (o: o, flatMapEntry: (...args: entryArgsWithIndex) => unknown) => void +> : ^^^^^^^ ^^^^^^^^^^^^^^^^^ ^^ ^^ ^^ ^^^^^^^^^ +>{ a: true, b: false } : { a: true; b: false; } +> : ^^^^^^^^^^^^^^^^^^^^^^ +>a : true +> : ^^^^ +>true : true +> : ^^^^ +>b : false +> : ^^^^^ +>false : false +> : ^^^^^ +>(k, v) => [k, v] : (k: "a" | "b", v: boolean) => (boolean | "a" | "b")[] +> : ^ ^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>k : "a" | "b" +> : ^^^^^^^^^ +>v : boolean +> : ^^^^^^^ +>[k, v] : (boolean | "a" | "b")[] +> : ^^^^^^^^^^^^^^^^^^^^^^^ +>k : "a" | "b" +> : ^^^^^^^^^ +>v : boolean +> : ^^^^^^^ + diff --git a/tests/cases/compiler/restTupleUnionShorterContextualParams.ts b/tests/cases/compiler/restTupleUnionShorterContextualParams.ts new file mode 100644 index 0000000000000..5b1ac908e79a9 --- /dev/null +++ b/tests/cases/compiler/restTupleUnionShorterContextualParams.ts @@ -0,0 +1,13 @@ +// @strict: true +// @noEmit: true + +// repro #48663 + +// showcase how those transitive assignments are OK +const f1: (x: string | number) => void = x => {}; +const f2: (x: string | number, y: string | number) => void = f1; +const f3: (...args: [number, string] | [string, number]) => void = f2; + +// by extension those should be OK too +const f4: (...args: [number, string] | [string, number]) => void = (item) => {} +const f5: (...args: [number, string] | [string, number]) => void = (item: number | string) => {} diff --git a/tests/cases/compiler/restTupleUnionWithRestContextualParams.ts b/tests/cases/compiler/restTupleUnionWithRestContextualParams.ts new file mode 100644 index 0000000000000..4c59964c19898 --- /dev/null +++ b/tests/cases/compiler/restTupleUnionWithRestContextualParams.ts @@ -0,0 +1,58 @@ +// @strict: true +// @noEmit: true + +const f1: (...args: [number, string, ...boolean[]] | [string, number, ...boolean[]]) => void = (a, b, c) => {}; + +const f2: (x: string, ...args: [string] | [number, boolean]) => void = (a, b, c) => {}; + +const f3: (...args: [type: "one"] | [type: "two", x: string]) => void = (type, x) => {} + +const f4: (...args: [type: "one", x?: number] | [type: "two", x: string]) => void = (type, x) => {} + +// #45972 +type Fn1 = (...args: [...strs: string[], num1: number, num2: number]) => void; +const f5: Fn1 = () => {} +const f6: Fn1 = (arg1) => {} +const f7: Fn1 = (arg1, arg2) => {} +const f8: Fn1 = (arg1, arg2, arg3) => {} + +// #45972#issuecomment-1140417029 +const f9: Fn1 = (...[arg1]: [string | number]) => {} +const f10: Fn1 = (...[arg1, arg2]: [string | number, string | number]) => {} +const f11: Fn1 = (...[arg1, arg2, arg3]: [string | number, string | number, string | number]) => {} + +const f12: (...args: [...strs: string[], num: number]) => void = (a, ...rest) => {} + +// #49218#pullrequestreview-1241473951 +const f13: (...rest: [number, ...T, boolean] ) => void = (a: number, ...arg: [...string[], boolean]) => {}; + +const f14: (...rest: [number, ...string[], T] ) => void = (a: number, ...arg: [...string[], boolean]) => {}; +const f15: (...rest: [number, ...T[], boolean] ) => void = (a: number, ...arg: [...string[], boolean]) => {}; + +const f16: (...rest: [...string[], number]) => void = (...rest: [...string[], number]) => {}; + +const f17: (...rest: [...string[], number]) => void = (a, b, c?) => {}; +const f18: (...rest: [...string[], number]) => void = (a, b, c?: string | number) => {}; + +const f19: (...rest: [string, ...boolean[], string] | [number]) => void = (a, ...rest) => {}; + +type entryArgsWithIndex = { + [k in keyof o]: [k: k, v: o[k], i: number]; +}[keyof o]; + +declare const iterateEntries1: ( + o: o, + flatMapEntry: (...args: entryArgsWithIndex) => void, +) => void; + +const ie1 = iterateEntries1({ a: true, b: false }, (k, v) => [k, v]); +const ie2 = iterateEntries1({ a: true, b: false }, (k, v) => { + return [k, v]; +}); + +declare const iterateEntries2: ( + o: o, + flatMapEntry: (...args: entryArgsWithIndex) => unknown, +) => void; + +const ie3 = iterateEntries2({ a: true, b: false }, (k, v) => [k, v]); diff --git a/tests/cases/conformance/controlFlow/dependentDestructuredVariables.ts b/tests/cases/conformance/controlFlow/dependentDestructuredVariables.ts index 67bce5559e9cf..4cd01440cc821 100644 --- a/tests/cases/conformance/controlFlow/dependentDestructuredVariables.ts +++ b/tests/cases/conformance/controlFlow/dependentDestructuredVariables.ts @@ -397,7 +397,7 @@ interface ClientEvents { warn: [message: string]; shardDisconnect: [closeEvent: CloseEvent, shardId: number]; } - + declare class Client { public on(event: K, listener: (...args: ClientEvents[K]) => void): void; } @@ -467,3 +467,11 @@ const parameterReassignedContextualRest1: (...args: [1, 2] | [3, 4]) => void = ( x; // 1 | 3 } } + +// repros from #47190#issuecomment-1339753554 +const f70: (...args: [type: "one"] | [type: "two", x: string]) => void = (type, x) => { + if (type !== "one") x.toUpperCase(); +} +const f71: (...args: [type: "one", x?: number] | [type: "two", x: string]) => void = (type, x) => { + if (type !== "one") x.toUpperCase(); +}