=== tests/cases/conformance/types/tuple/variadicTuples2.ts === // Declarations type V00 = [number, ...string[]]; >V00 : V00 type V01 = [...string[], number]; >V01 : V01 type V03 = [number, ...string[], number]; >V03 : V03 type V10 = [number, ...string[], ...boolean[]]; // Error >V10 : V10 type V11 = [number, ...string[], boolean?]; // Error >V11 : V11 type V12 = [number, string?, boolean]; // Error >V12 : V12 // Normalization type Tup3 = [...T, ...U, ...V]; >Tup3 : [...T, ...U, ...V] type V20 = Tup3<[number], string[], [number]>; // [number, ...string[], number] >V20 : [number, ...string[], number] type V21 = Tup3<[number], [string?], [boolean]>; // [number, string | undefined, boolean] >V21 : [number, string | undefined, boolean] type V22 = Tup3<[number], string[], boolean[]>; // [number, (string | boolean)[]] >V22 : [number, ...(string | boolean)[]] type V23 = Tup3<[number], string[], [boolean?]>; // [number, (string | boolean | undefined)[]] >V23 : [number, ...(string | boolean | undefined)[]] type V24 = Tup3<[number], [boolean?], string[]>; // [number, boolean?, ...string[]] >V24 : [number, (boolean | undefined)?, ...string[]] type V25 = Tup3; // (string | number | boolean)[] >V25 : (string | number | boolean)[] type V26 = Tup3; // [...(string | number)[], boolean] >V26 : [...(string | number)[], boolean] type V27 = Tup3<[number?], [string], [boolean?]>; // [number | undefined, string, boolean?] >V27 : [number | undefined, string, (boolean | undefined)?] type V30 = Tup3; // [...A, ...(string | number)[]] >V30 : [...A, ...(string | number)[]] type V31 = Tup3; // (string | number | A[number])[] >V31 : (string | number | A[number])[] type V32 = Tup3; // [...(string | number)[], ...A] >V32 : [...(string | number)[], ...A] type V40 = Tup3; // [...A, string?, ...number[]] >V40 : [...A, (string | undefined)?, ...number[]] type V41 = Tup3<[string?], A, number[]>; // [string?, ...A, ...number[]] >V41 : [(string | undefined)?, ...A, ...number[]] type V42 = Tup3<[string?], number[], A>; // [string?, ...number[], ...A] >V42 : [(string | undefined)?, ...number[], ...A] type V50 = Tup3; // [...A, ...(string | number | undefined)[]] >V50 : [...A, ...(string | number | undefined)[]] type V51 = Tup3; // (string | number | A[number] | undefined)[] >V51 : (string | number | A[number] | undefined)[] type V52 = Tup3; // [...(string | number | undefined)[], ...A] >V52 : [...(string | number | undefined)[], ...A] // Assignability declare let tt1: [...string[], number]; >tt1 : [...string[], number] tt1 = [5]; >tt1 = [5] : [number] >tt1 : [...string[], number] >[5] : [number] >5 : 5 tt1 = ['abc', 5]; >tt1 = ['abc', 5] : [string, number] >tt1 : [...string[], number] >['abc', 5] : [string, number] >'abc' : "abc" >5 : 5 tt1 = ['abc', 'def', 5]; >tt1 = ['abc', 'def', 5] : [string, string, number] >tt1 : [...string[], number] >['abc', 'def', 5] : [string, string, number] >'abc' : "abc" >'def' : "def" >5 : 5 tt1 = ['abc', 'def', 5, 6]; // Error >tt1 = ['abc', 'def', 5, 6] : [string, string, number, number] >tt1 : [...string[], number] >['abc', 'def', 5, 6] : [string, string, number, number] >'abc' : "abc" >'def' : "def" >5 : 5 >6 : 6 declare function ft1(...args: [...strs: string[], num: number]): void; >ft1 : (...args: [...strs: string[], num: number]) => void >args : [...strs: string[], num: number] ft1(5); >ft1(5) : void >ft1 : (...args: [...strs: string[], num: number]) => void >5 : 5 ft1('abc', 5); >ft1('abc', 5) : void >ft1 : (...args: [...strs: string[], num: number]) => void >'abc' : "abc" >5 : 5 ft1('abc', 'def', 5); >ft1('abc', 'def', 5) : void >ft1 : (...args: [...strs: string[], num: number]) => void >'abc' : "abc" >'def' : "def" >5 : 5 ft1('abc', 'def', 5, 6); // Error >ft1('abc', 'def', 5, 6) : void >ft1 : (...args: [...strs: string[], num: number]) => void >'abc' : "abc" >'def' : "def" >5 : 5 >6 : 6 declare let tt2: [number, ...string[], number]; >tt2 : [number, ...string[], number] tt2 = [0]; // Error >tt2 = [0] : [number] >tt2 : [number, ...string[], number] >[0] : [number] >0 : 0 tt2 = [0, 1]; >tt2 = [0, 1] : [number, number] >tt2 : [number, ...string[], number] >[0, 1] : [number, number] >0 : 0 >1 : 1 tt2 = [0, 1, 2]; // Error >tt2 = [0, 1, 2] : [number, number, number] >tt2 : [number, ...string[], number] >[0, 1, 2] : [number, number, number] >0 : 0 >1 : 1 >2 : 2 tt2 = [0, 'abc', 1]; >tt2 = [0, 'abc', 1] : [number, string, number] >tt2 : [number, ...string[], number] >[0, 'abc', 1] : [number, string, number] >0 : 0 >'abc' : "abc" >1 : 1 tt2 = [0, 'abc', 'def', 1]; >tt2 = [0, 'abc', 'def', 1] : [number, string, string, number] >tt2 : [number, ...string[], number] >[0, 'abc', 'def', 1] : [number, string, string, number] >0 : 0 >'abc' : "abc" >'def' : "def" >1 : 1 tt2 = [0, 'abc', 1, 'def']; // Error >tt2 = [0, 'abc', 1, 'def'] : [number, string, number, string] >tt2 : [number, ...string[], number] >[0, 'abc', 1, 'def'] : [number, string, number, string] >0 : 0 >'abc' : "abc" >1 : 1 >'def' : "def" tt2 = [true, 'abc', 'def', 1]; // Error >tt2 = [true, 'abc', 'def', 1] : [boolean, string, string, number] >tt2 : [number, ...string[], number] >[true, 'abc', 'def', 1] : [boolean, string, string, number] >true : true >'abc' : "abc" >'def' : "def" >1 : 1 tt2 = [0, 'abc', 'def', true]; // Error >tt2 = [0, 'abc', 'def', true] : [number, string, string, boolean] >tt2 : [number, ...string[], number] >[0, 'abc', 'def', true] : [number, string, string, boolean] >0 : 0 >'abc' : "abc" >'def' : "def" >true : true declare function ft2(n1: number, ...rest: [...strs: string[], n2: number]): void; >ft2 : (n1: number, ...rest: [...strs: string[], n2: number]) => void >n1 : number >rest : [...strs: string[], n2: number] ft2(0); // Error >ft2(0) : void >ft2 : (n1: number, ...rest: [...strs: string[], n2: number]) => void >0 : 0 ft2(0, 1); >ft2(0, 1) : void >ft2 : (n1: number, ...rest: [...strs: string[], n2: number]) => void >0 : 0 >1 : 1 ft2(0, 1, 2); // Error >ft2(0, 1, 2) : void >ft2 : (n1: number, ...rest: [...strs: string[], n2: number]) => void >0 : 0 >1 : 1 >2 : 2 ft2(0, 'abc', 1); >ft2(0, 'abc', 1) : void >ft2 : (n1: number, ...rest: [...strs: string[], n2: number]) => void >0 : 0 >'abc' : "abc" >1 : 1 ft2(0, 'abc', 'def', 1); >ft2(0, 'abc', 'def', 1) : void >ft2 : (n1: number, ...rest: [...strs: string[], n2: number]) => void >0 : 0 >'abc' : "abc" >'def' : "def" >1 : 1 ft2(0, 'abc', 1, 'def'); // Error >ft2(0, 'abc', 1, 'def') : void >ft2 : (n1: number, ...rest: [...strs: string[], n2: number]) => void >0 : 0 >'abc' : "abc" >1 : 1 >'def' : "def" ft2(true, 'abc', 'def', 1); // Error >ft2(true, 'abc', 'def', 1) : void >ft2 : (n1: number, ...rest: [...strs: string[], n2: number]) => void >true : true >'abc' : "abc" >'def' : "def" >1 : 1 ft2(0, 'abc', 'def', true); // Error >ft2(0, 'abc', 'def', true) : void >ft2 : (n1: number, ...rest: [...strs: string[], n2: number]) => void >0 : 0 >'abc' : "abc" >'def' : "def" >true : true function ft3(x: [number, ...T], y: [number, number], z: [number, ...number[]]) { >ft3 : (x: [number, ...T], y: [number, number], z: [number, ...number[]]) => void >x : [number, ...T] >y : [number, number] >z : [number, ...number[]] x = y; // Error >x = y : [number, number] >x : [number, ...T] >y : [number, number] x = z; // Error >x = z : [number, ...number[]] >x : [number, ...T] >z : [number, ...number[]] y = x; // Error >y = x : [number, ...T] >y : [number, number] >x : [number, ...T] z = x; // Error >z = x : [number, ...T] >z : [number, ...number[]] >x : [number, ...T] } // Inference function pipe(...args: [...T, (...values: T) => void]) { >pipe : (...args: [...T, (...values: T) => void]) => void >args : [...T, (...values: T) => void] >values : T const callback = args[args.length - 1] as (...values: T) => void; >callback : (...values: T) => void >args[args.length - 1] as (...values: T) => void : (...values: T) => void >args[args.length - 1] : [...T, (...values: T) => void][number] >args : [...T, (...values: T) => void] >args.length - 1 : number >args.length : number >args : [...T, (...values: T) => void] >length : number >1 : 1 >values : T const values = args.slice(0, -1) as unknown as T; >values : T >args.slice(0, -1) as unknown as T : T >args.slice(0, -1) as unknown : unknown >args.slice(0, -1) : (((...values: T) => void) | T[number])[] >args.slice : (start?: number | undefined, end?: number | undefined) => (((...values: T) => void) | T[number])[] >args : [...T, (...values: T) => void] >slice : (start?: number | undefined, end?: number | undefined) => (((...values: T) => void) | T[number])[] >0 : 0 >-1 : -1 >1 : 1 callback(...values); >callback(...values) : void >callback : (...values: T) => void >...values : unknown >values : T } pipe("foo", 123, true, (a, b, c) => { >pipe("foo", 123, true, (a, b, c) => { a; // string b; // number c; // boolean}) : void >pipe : (...args: [...T, (...values: T) => void]) => void >"foo" : "foo" >123 : 123 >true : true >(a, b, c) => { a; // string b; // number c; // boolean} : (a: string, b: number, c: boolean) => void >a : string >b : number >c : boolean a; // string >a : string b; // number >b : number c; // boolean >c : boolean }) pipe("foo", 123, true, (...x) => { >pipe("foo", 123, true, (...x) => { x; // [string, number, boolean]}) : void >pipe : (...args: [...T, (...values: T) => void]) => void >"foo" : "foo" >123 : 123 >true : true >(...x) => { x; // [string, number, boolean]} : (x_0: string, x_1: number, x_2: boolean) => void >x : [string, number, boolean] x; // [string, number, boolean] >x : [string, number, boolean] }); declare const sa: string[]; >sa : string[] pipe(...sa, (...x) => { >pipe(...sa, (...x) => { x; // string[]}) : void >pipe : (...args: [...T, (...values: T) => void]) => void >...sa : string >sa : string[] >(...x) => { x; // string[]} : (...x: string[]) => void >x : string[] x; // string[] >x : string[] }); pipe(1, ...sa, 2, (...x) => { >pipe(1, ...sa, 2, (...x) => { x; // [number, ...string[], number] let qq = x[x.length - 1]; let ww = x[0]}) : void >pipe : (...args: [...T, (...values: T) => void]) => void >1 : 1 >...sa : string >sa : string[] >2 : 2 >(...x) => { x; // [number, ...string[], number] let qq = x[x.length - 1]; let ww = x[0]} : (...x: [number, ...string[], number]) => void >x : [number, ...string[], number] x; // [number, ...string[], number] >x : [number, ...string[], number] let qq = x[x.length - 1]; >qq : string | number >x[x.length - 1] : string | number >x : [number, ...string[], number] >x.length - 1 : number >x.length : number >x : [number, ...string[], number] >length : number >1 : 1 let ww = x[0] >ww : number >x[0] : number >x : [number, ...string[], number] >0 : 0 }); pipe(1, 2, 3, 4); // Error >pipe(1, 2, 3, 4) : void >pipe : (...args: [...T, (...values: T) => void]) => void >1 : 1 >2 : 2 >3 : 3 >4 : 4 pipe(...sa); // Error >pipe(...sa) : void >pipe : (...args: [...T, (...values: T) => void]) => void >...sa : string >sa : string[] declare function fn1(t: [...unknown[], T, U]): [T, U]; >fn1 : (t: [...unknown[], T, U]) => [T, U] >t : [...unknown[], T, U] fn1([]); // Error >fn1([]) : [unknown, unknown] >fn1 : (t: [...unknown[], T, U]) => [T, U] >[] : [] fn1([1]); // Error >fn1([1]) : [unknown, unknown] >fn1 : (t: [...unknown[], T, U]) => [T, U] >[1] : [number] >1 : 1 fn1([1, 'abc']); // [number, string] >fn1([1, 'abc']) : [number, string] >fn1 : (t: [...unknown[], T, U]) => [T, U] >[1, 'abc'] : [number, string] >1 : 1 >'abc' : "abc" fn1([1, 'abc', true]); // [string, boolean] >fn1([1, 'abc', true]) : [string, boolean] >fn1 : (t: [...unknown[], T, U]) => [T, U] >[1, 'abc', true] : [number, string, boolean] >1 : 1 >'abc' : "abc" >true : true declare function fn2(t: [T, ...unknown[], U]): [T, U]; >fn2 : (t: [T, ...unknown[], U]) => [T, U] >t : [T, ...unknown[], U] fn2([]); // Error >fn2([]) : [unknown, unknown] >fn2 : (t: [T, ...unknown[], U]) => [T, U] >[] : [] fn2([1]); // Error >fn2([1]) : [unknown, unknown] >fn2 : (t: [T, ...unknown[], U]) => [T, U] >[1] : [number] >1 : 1 fn2([1, 'abc']); // [number, string] >fn2([1, 'abc']) : [number, string] >fn2 : (t: [T, ...unknown[], U]) => [T, U] >[1, 'abc'] : [number, string] >1 : 1 >'abc' : "abc" fn2([1, 'abc', true]); // [number, boolean] >fn2([1, 'abc', true]) : [number, boolean] >fn2 : (t: [T, ...unknown[], U]) => [T, U] >[1, 'abc', true] : [number, string, boolean] >1 : 1 >'abc' : "abc" >true : true // Repro from #39595 declare function foo(...stringsAndNumber: readonly [...S, number]): [...S, number]; >foo : (...stringsAndNumber: readonly [...S, number]) => [...S, number] >stringsAndNumber : readonly [...S, number] const a1 = foo('blah1', 1); >a1 : ["blah1", number] >foo('blah1', 1) : ["blah1", number] >foo : (...stringsAndNumber: readonly [...S, number]) => [...S, number] >'blah1' : "blah1" >1 : 1 const b1 = foo('blah1', 'blah2', 1); >b1 : ["blah1", "blah2", number] >foo('blah1', 'blah2', 1) : ["blah1", "blah2", number] >foo : (...stringsAndNumber: readonly [...S, number]) => [...S, number] >'blah1' : "blah1" >'blah2' : "blah2" >1 : 1 const c1 = foo(1); // Error >c1 : [string, ...string[], number] >foo(1) : [string, ...string[], number] >foo : (...stringsAndNumber: readonly [...S, number]) => [...S, number] >1 : 1 const d1 = foo(1, 2); // Error >d1 : [string, ...string[], number] >foo(1, 2) : [string, ...string[], number] >foo : (...stringsAndNumber: readonly [...S, number]) => [...S, number] >1 : 1 >2 : 2 const e1 = foo('blah1', 'blah2', 1, 2, 3); // Error >e1 : [string, ...string[], number] >foo('blah1', 'blah2', 1, 2, 3) : [string, ...string[], number] >foo : (...stringsAndNumber: readonly [...S, number]) => [...S, number] >'blah1' : "blah1" >'blah2' : "blah2" >1 : 1 >2 : 2 >3 : 3