Consistently error when rest element isn't last in tuple type (#40254)
* Consistently error when rest element isn't last in tuple type * Add regression test * Accept new baselines * Stricter circular recursion check in type inference * Revert "Stricter circular recursion check in type inference" This reverts commit80e6df6230
. * Revert "Accept new baselines" This reverts commit355706dadc
. * Accept new baselines
This commit is contained in:
parent
de5ef356b6
commit
cea1cfb82e
|
@ -31172,6 +31172,7 @@ namespace ts {
|
|||
function checkTupleType(node: TupleTypeNode) {
|
||||
const elementTypes = node.elements;
|
||||
let seenOptionalElement = false;
|
||||
let seenRestElement = false;
|
||||
const hasNamedElement = some(elementTypes, isNamedTupleMember);
|
||||
for (let i = 0; i < elementTypes.length; i++) {
|
||||
const e = elementTypes[i];
|
||||
|
@ -31181,16 +31182,17 @@ namespace ts {
|
|||
}
|
||||
const flags = getTupleElementFlags(e);
|
||||
if (flags & ElementFlags.Variadic) {
|
||||
if (!isArrayLikeType(getTypeFromTypeNode((<RestTypeNode | NamedTupleMember>e).type))) {
|
||||
const type = getTypeFromTypeNode((<RestTypeNode | NamedTupleMember>e).type);
|
||||
if (!isArrayLikeType(type)) {
|
||||
error(e, Diagnostics.A_rest_element_type_must_be_an_array_type);
|
||||
break;
|
||||
}
|
||||
if (isArrayType(type) || isTupleType(type) && type.target.combinedFlags & ElementFlags.Rest) {
|
||||
seenRestElement = true;
|
||||
}
|
||||
}
|
||||
else if (flags & ElementFlags.Rest) {
|
||||
if (i !== elementTypes.length - 1) {
|
||||
grammarErrorOnNode(e, Diagnostics.A_rest_element_must_be_last_in_a_tuple_type);
|
||||
break;
|
||||
}
|
||||
seenRestElement = true;
|
||||
}
|
||||
else if (flags & ElementFlags.Optional) {
|
||||
seenOptionalElement = true;
|
||||
|
@ -31199,6 +31201,10 @@ namespace ts {
|
|||
grammarErrorOnNode(e, Diagnostics.A_required_element_cannot_follow_an_optional_element);
|
||||
break;
|
||||
}
|
||||
if (seenRestElement && i !== elementTypes.length - 1) {
|
||||
grammarErrorOnNode(e, Diagnostics.A_rest_element_must_be_last_in_a_tuple_type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
forEach(node.elements, checkSourceElement);
|
||||
}
|
||||
|
|
|
@ -41,9 +41,12 @@ tests/cases/conformance/types/tuple/variadicTuples1.ts(203,5): error TS2322: Typ
|
|||
Type '"2"' is not assignable to type 'number | "0" | "length" | "toString" | "toLocaleString" | "pop" | "push" | "concat" | "join" | "reverse" | "shift" | "slice" | "sort" | "splice" | "unshift" | "indexOf" | "lastIndexOf" | "every" | "some" | "forEach" | "map" | "filter" | "reduce" | "reduceRight" | "1"'.
|
||||
tests/cases/conformance/types/tuple/variadicTuples1.ts(346,14): error TS7019: Rest parameter 'x' implicitly has an 'any[]' type.
|
||||
tests/cases/conformance/types/tuple/variadicTuples1.ts(354,26): error TS2322: Type 'string' is not assignable to type 'number | undefined'.
|
||||
tests/cases/conformance/types/tuple/variadicTuples1.ts(393,19): error TS1256: A rest element must be last in a tuple type.
|
||||
tests/cases/conformance/types/tuple/variadicTuples1.ts(396,20): error TS1256: A rest element must be last in a tuple type.
|
||||
tests/cases/conformance/types/tuple/variadicTuples1.ts(397,12): error TS1256: A rest element must be last in a tuple type.
|
||||
|
||||
|
||||
==== tests/cases/conformance/types/tuple/variadicTuples1.ts (20 errors) ====
|
||||
==== tests/cases/conformance/types/tuple/variadicTuples1.ts (23 errors) ====
|
||||
// Variadics in tuple types
|
||||
|
||||
type TV0<T extends unknown[]> = [string, ...T];
|
||||
|
@ -496,4 +499,20 @@ tests/cases/conformance/types/tuple/variadicTuples1.ts(354,26): error TS2322: Ty
|
|||
|
||||
callApi(getUser);
|
||||
callApi(getOrgUser);
|
||||
|
||||
// Repro from #40235
|
||||
|
||||
type Numbers = number[];
|
||||
type Unbounded = [...Numbers, boolean];
|
||||
~~~~~~~~~~
|
||||
!!! error TS1256: A rest element must be last in a tuple type.
|
||||
const data: Unbounded = [false, false];
|
||||
|
||||
type U1 = [string, ...Numbers, boolean];
|
||||
~~~~~~~~~~
|
||||
!!! error TS1256: A rest element must be last in a tuple type.
|
||||
type U2 = [...[string, ...Numbers], boolean];
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
!!! error TS1256: A rest element must be last in a tuple type.
|
||||
type U3 = [...[string, number], boolean];
|
||||
|
|
@ -387,6 +387,16 @@ function callApi<T extends unknown[] = [], U = void>(method: (...args: [...T, ob
|
|||
|
||||
callApi(getUser);
|
||||
callApi(getOrgUser);
|
||||
|
||||
// Repro from #40235
|
||||
|
||||
type Numbers = number[];
|
||||
type Unbounded = [...Numbers, boolean];
|
||||
const data: Unbounded = [false, false];
|
||||
|
||||
type U1 = [string, ...Numbers, boolean];
|
||||
type U2 = [...[string, ...Numbers], boolean];
|
||||
type U3 = [...[string, number], boolean];
|
||||
|
||||
|
||||
//// [variadicTuples1.js]
|
||||
|
@ -609,6 +619,7 @@ function callApi(method) {
|
|||
}
|
||||
callApi(getUser);
|
||||
callApi(getOrgUser);
|
||||
var data = [false, false];
|
||||
|
||||
|
||||
//// [variadicTuples1.d.ts]
|
||||
|
@ -774,3 +785,9 @@ declare function getOrgUser(id: string, orgId: number, options?: {
|
|||
z?: boolean;
|
||||
}): void;
|
||||
declare function callApi<T extends unknown[] = [], U = void>(method: (...args: [...T, object]) => U): (...args_0: T) => U;
|
||||
declare type Numbers = number[];
|
||||
declare type Unbounded = [...Numbers, boolean];
|
||||
declare const data: Unbounded;
|
||||
declare type U1 = [string, ...Numbers, boolean];
|
||||
declare type U2 = [...[string, ...Numbers], boolean];
|
||||
declare type U3 = [...[string, number], boolean];
|
||||
|
|
|
@ -1327,3 +1327,27 @@ callApi(getOrgUser);
|
|||
>callApi : Symbol(callApi, Decl(variadicTuples1.ts, 380, 100))
|
||||
>getOrgUser : Symbol(getOrgUser, Decl(variadicTuples1.ts, 378, 71))
|
||||
|
||||
// Repro from #40235
|
||||
|
||||
type Numbers = number[];
|
||||
>Numbers : Symbol(Numbers, Decl(variadicTuples1.ts, 387, 20))
|
||||
|
||||
type Unbounded = [...Numbers, boolean];
|
||||
>Unbounded : Symbol(Unbounded, Decl(variadicTuples1.ts, 391, 24))
|
||||
>Numbers : Symbol(Numbers, Decl(variadicTuples1.ts, 387, 20))
|
||||
|
||||
const data: Unbounded = [false, false];
|
||||
>data : Symbol(data, Decl(variadicTuples1.ts, 393, 5))
|
||||
>Unbounded : Symbol(Unbounded, Decl(variadicTuples1.ts, 391, 24))
|
||||
|
||||
type U1 = [string, ...Numbers, boolean];
|
||||
>U1 : Symbol(U1, Decl(variadicTuples1.ts, 393, 39))
|
||||
>Numbers : Symbol(Numbers, Decl(variadicTuples1.ts, 387, 20))
|
||||
|
||||
type U2 = [...[string, ...Numbers], boolean];
|
||||
>U2 : Symbol(U2, Decl(variadicTuples1.ts, 395, 40))
|
||||
>Numbers : Symbol(Numbers, Decl(variadicTuples1.ts, 387, 20))
|
||||
|
||||
type U3 = [...[string, number], boolean];
|
||||
>U3 : Symbol(U3, Decl(variadicTuples1.ts, 396, 45))
|
||||
|
||||
|
|
|
@ -1383,3 +1383,26 @@ callApi(getOrgUser);
|
|||
>callApi : <T extends unknown[] = [], U = void>(method: (...args_0: T, args_1: object) => U) => (...args_0: T) => U
|
||||
>getOrgUser : (id: string, orgId: number, options?: { y?: number | undefined; z?: boolean | undefined; } | undefined) => void
|
||||
|
||||
// Repro from #40235
|
||||
|
||||
type Numbers = number[];
|
||||
>Numbers : Numbers
|
||||
|
||||
type Unbounded = [...Numbers, boolean];
|
||||
>Unbounded : (number | boolean)[]
|
||||
|
||||
const data: Unbounded = [false, false];
|
||||
>data : (number | boolean)[]
|
||||
>[false, false] : false[]
|
||||
>false : false
|
||||
>false : false
|
||||
|
||||
type U1 = [string, ...Numbers, boolean];
|
||||
>U1 : [string, ...(number | boolean)[]]
|
||||
|
||||
type U2 = [...[string, ...Numbers], boolean];
|
||||
>U2 : [string, ...(number | boolean)[]]
|
||||
|
||||
type U3 = [...[string, number], boolean];
|
||||
>U3 : [string, number, boolean]
|
||||
|
||||
|
|
|
@ -389,3 +389,13 @@ function callApi<T extends unknown[] = [], U = void>(method: (...args: [...T, ob
|
|||
|
||||
callApi(getUser);
|
||||
callApi(getOrgUser);
|
||||
|
||||
// Repro from #40235
|
||||
|
||||
type Numbers = number[];
|
||||
type Unbounded = [...Numbers, boolean];
|
||||
const data: Unbounded = [false, false];
|
||||
|
||||
type U1 = [string, ...Numbers, boolean];
|
||||
type U2 = [...[string, ...Numbers], boolean];
|
||||
type U3 = [...[string, number], boolean];
|
||||
|
|
Loading…
Reference in a new issue