* Support starting and middle rest elements in tuples * Accept new baselines * Include all rest arguments in error span * Accept new baselines * Fix tests * Add new tests * Fix lint errors
133 lines
4.5 KiB
TypeScript
133 lines
4.5 KiB
TypeScript
// @strict: true
|
|
// @declaration: true
|
|
|
|
// Declarations
|
|
|
|
type V00 = [number, ...string[]];
|
|
type V01 = [...string[], number];
|
|
type V03 = [number, ...string[], number];
|
|
|
|
type V10 = [number, ...string[], ...boolean[]]; // Error
|
|
type V11 = [number, ...string[], boolean?]; // Error
|
|
type V12 = [number, string?, boolean]; // Error
|
|
|
|
// Normalization
|
|
|
|
type Tup3<T extends unknown[], U extends unknown[], V extends unknown[]> = [...T, ...U, ...V];
|
|
|
|
type V20 = Tup3<[number], string[], [number]>; // [number, ...string[], number]
|
|
type V21 = Tup3<[number], [string?], [boolean]>; // [number, string | undefined, boolean]
|
|
type V22 = Tup3<[number], string[], boolean[]>; // [number, (string | boolean)[]]
|
|
type V23 = Tup3<[number], string[], [boolean?]>; // [number, (string | boolean | undefined)[]]
|
|
type V24 = Tup3<[number], [boolean?], string[]>; // [number, boolean?, ...string[]]
|
|
type V25 = Tup3<string[], number[], boolean[]>; // (string | number | boolean)[]
|
|
type V26 = Tup3<string[], number[], [boolean]>; // [...(string | number)[], boolean]
|
|
type V27 = Tup3<[number?], [string], [boolean?]>; // [number | undefined, string, boolean?]
|
|
|
|
type V30<A extends unknown[]> = Tup3<A, string[], number[]>; // [...A, ...(string | number)[]]
|
|
type V31<A extends unknown[]> = Tup3<string[], A, number[]>; // (string | number | A[number])[]
|
|
type V32<A extends unknown[]> = Tup3<string[], number[], A>; // [...(string | number)[], ...A]
|
|
|
|
type V40<A extends unknown[]> = Tup3<A, [string?], number[]>; // [...A, string?, ...number[]]
|
|
type V41<A extends unknown[]> = Tup3<[string?], A, number[]>; // [string?, ...A, ...number[]]
|
|
type V42<A extends unknown[]> = Tup3<[string?], number[], A>; // [string?, ...number[], ...A]
|
|
|
|
type V50<A extends unknown[]> = Tup3<A, string[], [number?]>; // [...A, ...(string | number | undefined)[]]
|
|
type V51<A extends unknown[]> = Tup3<string[], A, [number?]>; // (string | number | A[number] | undefined)[]
|
|
type V52<A extends unknown[]> = Tup3<string[], [number?], A>; // [...(string | number | undefined)[], ...A]
|
|
|
|
// Assignability
|
|
|
|
declare let tt1: [...string[], number];
|
|
tt1 = [5];
|
|
tt1 = ['abc', 5];
|
|
tt1 = ['abc', 'def', 5];
|
|
tt1 = ['abc', 'def', 5, 6]; // Error
|
|
|
|
declare function ft1(...args: [...strs: string[], num: number]): void;
|
|
ft1(5);
|
|
ft1('abc', 5);
|
|
ft1('abc', 'def', 5);
|
|
ft1('abc', 'def', 5, 6); // Error
|
|
|
|
declare let tt2: [number, ...string[], number];
|
|
tt2 = [0]; // Error
|
|
tt2 = [0, 1];
|
|
tt2 = [0, 1, 2]; // Error
|
|
tt2 = [0, 'abc', 1];
|
|
tt2 = [0, 'abc', 'def', 1];
|
|
tt2 = [0, 'abc', 1, 'def']; // Error
|
|
tt2 = [true, 'abc', 'def', 1]; // Error
|
|
tt2 = [0, 'abc', 'def', true]; // Error
|
|
|
|
declare function ft2(n1: number, ...rest: [...strs: string[], n2: number]): void;
|
|
ft2(0); // Error
|
|
ft2(0, 1);
|
|
ft2(0, 1, 2); // Error
|
|
ft2(0, 'abc', 1);
|
|
ft2(0, 'abc', 'def', 1);
|
|
ft2(0, 'abc', 1, 'def'); // Error
|
|
ft2(true, 'abc', 'def', 1); // Error
|
|
ft2(0, 'abc', 'def', true); // Error
|
|
|
|
function ft3<T extends unknown[]>(x: [number, ...T], y: [number, number], z: [number, ...number[]]) {
|
|
x = y; // Error
|
|
x = z; // Error
|
|
y = x; // Error
|
|
z = x; // Error
|
|
}
|
|
|
|
// Inference
|
|
|
|
function pipe<T extends readonly unknown[]>(...args: [...T, (...values: T) => void]) {
|
|
const callback = args[args.length - 1] as (...values: T) => void;
|
|
const values = args.slice(0, -1) as unknown as T;
|
|
callback(...values);
|
|
}
|
|
|
|
pipe("foo", 123, true, (a, b, c) => {
|
|
a; // string
|
|
b; // number
|
|
c; // boolean
|
|
})
|
|
|
|
pipe("foo", 123, true, (...x) => {
|
|
x; // [string, number, boolean]
|
|
});
|
|
|
|
declare const sa: string[];
|
|
|
|
pipe(...sa, (...x) => {
|
|
x; // string[]
|
|
});
|
|
|
|
pipe(1, ...sa, 2, (...x) => {
|
|
x; // [number, ...string[], number]
|
|
let qq = x[x.length - 1];
|
|
let ww = x[0]
|
|
});
|
|
|
|
pipe<number[]>(1, 2, 3, 4); // Error
|
|
pipe(...sa); // Error
|
|
|
|
declare function fn1<T, U>(t: [...unknown[], T, U]): [T, U];
|
|
fn1([]); // Error
|
|
fn1([1]); // Error
|
|
fn1([1, 'abc']); // [number, string]
|
|
fn1([1, 'abc', true]); // [string, boolean]
|
|
|
|
declare function fn2<T, U>(t: [T, ...unknown[], U]): [T, U];
|
|
fn2([]); // Error
|
|
fn2([1]); // Error
|
|
fn2([1, 'abc']); // [number, string]
|
|
fn2([1, 'abc', true]); // [number, boolean]
|
|
|
|
// Repro from #39595
|
|
|
|
declare function foo<S extends readonly [string, ...string[]]>(...stringsAndNumber: readonly [...S, number]): [...S, number];
|
|
|
|
const a1 = foo('blah1', 1);
|
|
const b1 = foo('blah1', 'blah2', 1);
|
|
const c1 = foo(1); // Error
|
|
const d1 = foo(1, 2); // Error
|
|
const e1 = foo('blah1', 'blah2', 1, 2, 3); // Error
|