Skip to content

Commit 458eae0

Browse files
authored
Revise mapped tuple type instantiation logic (#57031)
1 parent 4a34f45 commit 458eae0

11 files changed

+612
-257
lines changed

src/compiler/checker.ts

+29-39
Original file line numberDiff line numberDiff line change
@@ -19759,11 +19759,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
1975919759
) {
1976019760
return instantiateMappedArrayType(t, type, prependTypeMapping(typeVariable, t, mapper));
1976119761
}
19762-
if (isGenericTupleType(t)) {
19763-
return instantiateMappedGenericTupleType(t, type, typeVariable, mapper);
19764-
}
1976519762
if (isTupleType(t)) {
19766-
return instantiateMappedTupleType(t, type, prependTypeMapping(typeVariable, t, mapper));
19763+
return instantiateMappedTupleType(t, type, typeVariable, mapper);
1976719764
}
1976819765
}
1976919766
return instantiateAnonymousType(type, prependTypeMapping(typeVariable, t, mapper));
@@ -19783,26 +19780,32 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
1978319780
return modifiers & MappedTypeModifiers.IncludeReadonly ? true : modifiers & MappedTypeModifiers.ExcludeReadonly ? false : state;
1978419781
}
1978519782

19786-
function instantiateMappedGenericTupleType(tupleType: TupleTypeReference, mappedType: MappedType, typeVariable: TypeVariable, mapper: TypeMapper) {
19787-
// When a tuple type is generic (i.e. when it contains variadic elements), we want to eagerly map the
19788-
// non-generic elements and defer mapping the generic elements. In order to facilitate this, we transform
19789-
// M<[A, B?, ...T, ...C[]] into [...M<[A]>, ...M<[B?]>, ...M<T>, ...M<C[]>] and then rely on tuple type
19790-
// normalization to resolve the non-generic parts of the resulting tuple.
19783+
function instantiateMappedTupleType(tupleType: TupleTypeReference, mappedType: MappedType, typeVariable: TypeVariable, mapper: TypeMapper) {
19784+
// We apply the mapped type's template type to each of the fixed part elements. For variadic elements, we
19785+
// apply the mapped type itself to the variadic element type. For other elements in the variable part of the
19786+
// tuple, we surround the element type with an array type and apply the mapped type to that. This ensures
19787+
// that we get sequential property key types for the fixed part of the tuple, and property key type number
19788+
// for the remaining elements. For example
19789+
//
19790+
// type Keys<T> = { [K in keyof T]: K };
19791+
// type Foo<T extends any[]> = Keys<[string, string, ...T, string]>; // ["0", "1", ...Keys<T>, number]
19792+
//
1979119793
const elementFlags = tupleType.target.elementFlags;
19792-
const elementTypes = map(getElementTypes(tupleType), (t, i) => {
19793-
const singleton = elementFlags[i] & ElementFlags.Variadic ? t :
19794-
elementFlags[i] & ElementFlags.Rest ? createArrayType(t) :
19795-
createTupleType([t], [elementFlags[i]]);
19796-
// avoid infinite recursion, if the singleton is the type variable itself
19797-
// then we'd just get back here with the same arguments from within instantiateMappedType
19798-
if (singleton === typeVariable) {
19799-
return mappedType;
19800-
}
19801-
// The singleton is never a generic tuple type, so it is safe to recurse here.
19802-
return instantiateMappedType(mappedType, prependTypeMapping(typeVariable, singleton, mapper));
19794+
const fixedLength = tupleType.target.fixedLength;
19795+
const fixedMapper = fixedLength ? prependTypeMapping(typeVariable, tupleType, mapper) : mapper;
19796+
const newElementTypes = map(getElementTypes(tupleType), (type, i) => {
19797+
const flags = elementFlags[i];
19798+
return i < fixedLength ? instantiateMappedTypeTemplate(mappedType, getStringLiteralType("" + i), !!(flags & ElementFlags.Optional), fixedMapper) :
19799+
flags & ElementFlags.Variadic ? instantiateType(mappedType, prependTypeMapping(typeVariable, type, mapper)) :
19800+
getElementTypeOfArrayType(instantiateType(mappedType, prependTypeMapping(typeVariable, createArrayType(type), mapper))) ?? unknownType;
1980319801
});
19802+
const modifiers = getMappedTypeModifiers(mappedType);
19803+
const newElementFlags = modifiers & MappedTypeModifiers.IncludeOptional ? map(elementFlags, f => f & ElementFlags.Required ? ElementFlags.Optional : f) :
19804+
modifiers & MappedTypeModifiers.ExcludeOptional ? map(elementFlags, f => f & ElementFlags.Optional ? ElementFlags.Required : f) :
19805+
elementFlags;
1980419806
const newReadonly = getModifiedReadonlyState(tupleType.target.readonly, getMappedTypeModifiers(mappedType));
19805-
return createTupleType(elementTypes, map(elementTypes, _ => ElementFlags.Variadic), newReadonly);
19807+
return contains(newElementTypes, errorType) ? errorType :
19808+
createTupleType(newElementTypes, newElementFlags, newReadonly, tupleType.target.labeledElementDeclarations);
1980619809
}
1980719810

1980819811
function instantiateMappedArrayType(arrayType: Type, mappedType: MappedType, mapper: TypeMapper) {
@@ -19811,18 +19814,6 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
1981119814
createArrayType(elementType, getModifiedReadonlyState(isReadonlyArrayType(arrayType), getMappedTypeModifiers(mappedType)));
1981219815
}
1981319816

19814-
function instantiateMappedTupleType(tupleType: TupleTypeReference, mappedType: MappedType, mapper: TypeMapper) {
19815-
const elementFlags = tupleType.target.elementFlags;
19816-
const elementTypes = map(getElementTypes(tupleType), (_, i) => instantiateMappedTypeTemplate(mappedType, getStringLiteralType("" + i), !!(elementFlags[i] & ElementFlags.Optional), mapper));
19817-
const modifiers = getMappedTypeModifiers(mappedType);
19818-
const newTupleModifiers = modifiers & MappedTypeModifiers.IncludeOptional ? map(elementFlags, f => f & ElementFlags.Required ? ElementFlags.Optional : f) :
19819-
modifiers & MappedTypeModifiers.ExcludeOptional ? map(elementFlags, f => f & ElementFlags.Optional ? ElementFlags.Required : f) :
19820-
elementFlags;
19821-
const newReadonly = getModifiedReadonlyState(tupleType.target.readonly, modifiers);
19822-
return contains(elementTypes, errorType) ? errorType :
19823-
createTupleType(elementTypes, newTupleModifiers, newReadonly, tupleType.target.labeledElementDeclarations);
19824-
}
19825-
1982619817
function instantiateMappedTypeTemplate(type: MappedType, key: Type, isOptional: boolean, mapper: TypeMapper) {
1982719818
const templateMapper = appendTypeMapping(mapper, getTypeParameterFromMappedType(type), key);
1982819819
const propType = instantiateType(getTemplateTypeFromMappedType(type.target as MappedType || type), templateMapper);
@@ -40441,22 +40432,21 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
4044140432
}
4044240433

4044340434
function checkTupleType(node: TupleTypeNode) {
40444-
const elementTypes = node.elements;
4044540435
let seenOptionalElement = false;
4044640436
let seenRestElement = false;
40447-
for (const e of elementTypes) {
40448-
const flags = getTupleElementFlags(e);
40437+
for (const e of node.elements) {
40438+
let flags = getTupleElementFlags(e);
4044940439
if (flags & ElementFlags.Variadic) {
4045040440
const type = getTypeFromTypeNode((e as RestTypeNode | NamedTupleMember).type);
4045140441
if (!isArrayLikeType(type)) {
4045240442
error(e, Diagnostics.A_rest_element_type_must_be_an_array_type);
4045340443
break;
4045440444
}
4045540445
if (isArrayType(type) || isTupleType(type) && type.target.combinedFlags & ElementFlags.Rest) {
40456-
seenRestElement = true;
40446+
flags |= ElementFlags.Rest;
4045740447
}
4045840448
}
40459-
else if (flags & ElementFlags.Rest) {
40449+
if (flags & ElementFlags.Rest) {
4046040450
if (seenRestElement) {
4046140451
grammarErrorOnNode(e, Diagnostics.A_rest_element_cannot_follow_another_rest_element);
4046240452
break;
@@ -40470,7 +40460,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
4047040460
}
4047140461
seenOptionalElement = true;
4047240462
}
40473-
else if (seenOptionalElement) {
40463+
else if (flags & ElementFlags.Required && seenOptionalElement) {
4047440464
grammarErrorOnNode(e, Diagnostics.A_required_element_cannot_follow_an_optional_element);
4047540465
break;
4047640466
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
circularInlineMappedGenericTupleTypeNoCrash.ts(11,12): error TS2589: Type instantiation is excessively deep and possibly infinite.
2+
3+
4+
==== circularInlineMappedGenericTupleTypeNoCrash.ts (1 errors) ====
5+
class Foo<Elements extends readonly unknown[]> {
6+
public readonly elements: { [P in keyof Elements]: { bar: Elements[P] } };
7+
8+
public constructor(
9+
...elements: { [P in keyof Elements]: { bar: Elements[P] } }
10+
) {
11+
this.elements = elements;
12+
}
13+
14+
public add(): Foo<[...Elements, "abc"]> {
15+
return new Foo<[...Elements, "abc"]>(...this.elements, { bar: "abc" });
16+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
17+
!!! error TS2589: Type instantiation is excessively deep and possibly infinite.
18+
}
19+
}
20+

tests/baselines/reference/circularInlineMappedGenericTupleTypeNoCrash.types

+2-2
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,8 @@ class Foo<Elements extends readonly unknown[]> {
3232
>this.elements : { [P in keyof Elements]: { bar: Elements[P]; }; }
3333
>this : this
3434
>elements : { [P in keyof Elements]: { bar: Elements[P]; }; }
35-
>{ bar: "abc" } : { bar: "abc"; }
36-
>bar : "abc"
35+
>{ bar: "abc" } : { bar: string; }
36+
>bar : string
3737
>"abc" : "abc"
3838
}
3939
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
//// [tests/cases/conformance/types/mapped/mappedTypesGenericTuples.ts] ////
2+
3+
=== mappedTypesGenericTuples.ts ===
4+
// Property keys are `number` following the fixed part of a tuple
5+
6+
type K<T> = { [P in keyof T]: P };
7+
>K : Symbol(K, Decl(mappedTypesGenericTuples.ts, 0, 0))
8+
>T : Symbol(T, Decl(mappedTypesGenericTuples.ts, 2, 7))
9+
>P : Symbol(P, Decl(mappedTypesGenericTuples.ts, 2, 15))
10+
>T : Symbol(T, Decl(mappedTypesGenericTuples.ts, 2, 7))
11+
>P : Symbol(P, Decl(mappedTypesGenericTuples.ts, 2, 15))
12+
13+
type M<T> = { [P in keyof T]: T[P] };
14+
>M : Symbol(M, Decl(mappedTypesGenericTuples.ts, 2, 34))
15+
>T : Symbol(T, Decl(mappedTypesGenericTuples.ts, 3, 7))
16+
>P : Symbol(P, Decl(mappedTypesGenericTuples.ts, 3, 15))
17+
>T : Symbol(T, Decl(mappedTypesGenericTuples.ts, 3, 7))
18+
>T : Symbol(T, Decl(mappedTypesGenericTuples.ts, 3, 7))
19+
>P : Symbol(P, Decl(mappedTypesGenericTuples.ts, 3, 15))
20+
21+
type KA = K<[string, string, boolean]>; // ["0", "1", "2"]
22+
>KA : Symbol(KA, Decl(mappedTypesGenericTuples.ts, 3, 37))
23+
>K : Symbol(K, Decl(mappedTypesGenericTuples.ts, 0, 0))
24+
25+
type KB = K<[string, string, ...string[], string]>; // ["0", "1", ...number[], number]
26+
>KB : Symbol(KB, Decl(mappedTypesGenericTuples.ts, 5, 39))
27+
>K : Symbol(K, Decl(mappedTypesGenericTuples.ts, 0, 0))
28+
29+
type KC = K<[...string[]]>; // number[]
30+
>KC : Symbol(KC, Decl(mappedTypesGenericTuples.ts, 6, 51))
31+
>K : Symbol(K, Decl(mappedTypesGenericTuples.ts, 0, 0))
32+
33+
type KD = K<string[]>; // number[]
34+
>KD : Symbol(KD, Decl(mappedTypesGenericTuples.ts, 7, 27))
35+
>K : Symbol(K, Decl(mappedTypesGenericTuples.ts, 0, 0))
36+
37+
type A = { a: string };
38+
>A : Symbol(A, Decl(mappedTypesGenericTuples.ts, 8, 22))
39+
>a : Symbol(a, Decl(mappedTypesGenericTuples.ts, 10, 10))
40+
41+
type B = { b: string };
42+
>B : Symbol(B, Decl(mappedTypesGenericTuples.ts, 10, 23))
43+
>b : Symbol(b, Decl(mappedTypesGenericTuples.ts, 11, 10))
44+
45+
type C = { c: string };
46+
>C : Symbol(C, Decl(mappedTypesGenericTuples.ts, 11, 23))
47+
>c : Symbol(c, Decl(mappedTypesGenericTuples.ts, 12, 10))
48+
49+
type D = { d: string };
50+
>D : Symbol(D, Decl(mappedTypesGenericTuples.ts, 12, 23))
51+
>d : Symbol(d, Decl(mappedTypesGenericTuples.ts, 13, 10))
52+
53+
type V0<T extends unknown[]> = [A, B?, ...T, ...C[]]
54+
>V0 : Symbol(V0, Decl(mappedTypesGenericTuples.ts, 13, 23))
55+
>T : Symbol(T, Decl(mappedTypesGenericTuples.ts, 15, 8))
56+
>A : Symbol(A, Decl(mappedTypesGenericTuples.ts, 8, 22))
57+
>B : Symbol(B, Decl(mappedTypesGenericTuples.ts, 10, 23))
58+
>T : Symbol(T, Decl(mappedTypesGenericTuples.ts, 15, 8))
59+
>C : Symbol(C, Decl(mappedTypesGenericTuples.ts, 11, 23))
60+
61+
type V1<T extends unknown[]> = [A, ...T, B, ...C[], D]
62+
>V1 : Symbol(V1, Decl(mappedTypesGenericTuples.ts, 15, 52))
63+
>T : Symbol(T, Decl(mappedTypesGenericTuples.ts, 16, 8))
64+
>A : Symbol(A, Decl(mappedTypesGenericTuples.ts, 8, 22))
65+
>T : Symbol(T, Decl(mappedTypesGenericTuples.ts, 16, 8))
66+
>B : Symbol(B, Decl(mappedTypesGenericTuples.ts, 10, 23))
67+
>C : Symbol(C, Decl(mappedTypesGenericTuples.ts, 11, 23))
68+
>D : Symbol(D, Decl(mappedTypesGenericTuples.ts, 12, 23))
69+
70+
type K0<T extends unknown[]> = K<V0<T>>; // ["0", "1"?, ...K<T>, ...number[]]
71+
>K0 : Symbol(K0, Decl(mappedTypesGenericTuples.ts, 16, 54))
72+
>T : Symbol(T, Decl(mappedTypesGenericTuples.ts, 18, 8))
73+
>K : Symbol(K, Decl(mappedTypesGenericTuples.ts, 0, 0))
74+
>V0 : Symbol(V0, Decl(mappedTypesGenericTuples.ts, 13, 23))
75+
>T : Symbol(T, Decl(mappedTypesGenericTuples.ts, 18, 8))
76+
77+
type K1<T extends unknown[]> = K<V1<T>>; // ["0", ...K<T>, number, ...number[], number]
78+
>K1 : Symbol(K1, Decl(mappedTypesGenericTuples.ts, 18, 40))
79+
>T : Symbol(T, Decl(mappedTypesGenericTuples.ts, 19, 8))
80+
>K : Symbol(K, Decl(mappedTypesGenericTuples.ts, 0, 0))
81+
>V1 : Symbol(V1, Decl(mappedTypesGenericTuples.ts, 15, 52))
82+
>T : Symbol(T, Decl(mappedTypesGenericTuples.ts, 19, 8))
83+
84+
type M0<T extends unknown[]> = M<V0<T>>; // [A, B?, ...M<T>, ...C[]]
85+
>M0 : Symbol(M0, Decl(mappedTypesGenericTuples.ts, 19, 40))
86+
>T : Symbol(T, Decl(mappedTypesGenericTuples.ts, 21, 8))
87+
>M : Symbol(M, Decl(mappedTypesGenericTuples.ts, 2, 34))
88+
>V0 : Symbol(V0, Decl(mappedTypesGenericTuples.ts, 13, 23))
89+
>T : Symbol(T, Decl(mappedTypesGenericTuples.ts, 21, 8))
90+
91+
type M1<T extends unknown[]> = M<V1<T>>; // [A, ...M<T>, B, ...C[], D]
92+
>M1 : Symbol(M1, Decl(mappedTypesGenericTuples.ts, 21, 40))
93+
>T : Symbol(T, Decl(mappedTypesGenericTuples.ts, 22, 8))
94+
>M : Symbol(M, Decl(mappedTypesGenericTuples.ts, 2, 34))
95+
>V1 : Symbol(V1, Decl(mappedTypesGenericTuples.ts, 15, 52))
96+
>T : Symbol(T, Decl(mappedTypesGenericTuples.ts, 22, 8))
97+
98+
// Repro from #48856
99+
100+
type Keys<O extends unknown[]> = { [K in keyof O]: K };
101+
>Keys : Symbol(Keys, Decl(mappedTypesGenericTuples.ts, 22, 40))
102+
>O : Symbol(O, Decl(mappedTypesGenericTuples.ts, 26, 10))
103+
>K : Symbol(K, Decl(mappedTypesGenericTuples.ts, 26, 36))
104+
>O : Symbol(O, Decl(mappedTypesGenericTuples.ts, 26, 10))
105+
>K : Symbol(K, Decl(mappedTypesGenericTuples.ts, 26, 36))
106+
107+
type Keys1 = Keys<[string, ...string[]]>;
108+
>Keys1 : Symbol(Keys1, Decl(mappedTypesGenericTuples.ts, 26, 55))
109+
>Keys : Symbol(Keys, Decl(mappedTypesGenericTuples.ts, 22, 40))
110+
111+
type Keys2 = Keys<[string, ...string[], number]>;
112+
>Keys2 : Symbol(Keys2, Decl(mappedTypesGenericTuples.ts, 28, 41))
113+
>Keys : Symbol(Keys, Decl(mappedTypesGenericTuples.ts, 22, 40))
114+
115+
// Repro from #56888
116+
117+
type T1 = ['a', 'b', 'c'] extends readonly [infer H, ...unknown[]] ? H : never; // "a"
118+
>T1 : Symbol(T1, Decl(mappedTypesGenericTuples.ts, 29, 49))
119+
>H : Symbol(H, Decl(mappedTypesGenericTuples.ts, 33, 49))
120+
>H : Symbol(H, Decl(mappedTypesGenericTuples.ts, 33, 49))
121+
122+
type T2 = ['a', 'b', 'c'] extends Readonly<[infer H, ...unknown[]]> ? H : never; // "a"
123+
>T2 : Symbol(T2, Decl(mappedTypesGenericTuples.ts, 33, 79))
124+
>Readonly : Symbol(Readonly, Decl(lib.es5.d.ts, --, --))
125+
>H : Symbol(H, Decl(mappedTypesGenericTuples.ts, 34, 49))
126+
>H : Symbol(H, Decl(mappedTypesGenericTuples.ts, 34, 49))
127+
128+
type T3 = ['a', 'b', 'c'] extends readonly [...unknown[], infer L] ? L : never; // "c"
129+
>T3 : Symbol(T3, Decl(mappedTypesGenericTuples.ts, 34, 80))
130+
>L : Symbol(L, Decl(mappedTypesGenericTuples.ts, 35, 63))
131+
>L : Symbol(L, Decl(mappedTypesGenericTuples.ts, 35, 63))
132+
133+
type T4 = ['a', 'b', 'c'] extends Readonly<[...unknown[], infer L]> ? L : never; // "c"
134+
>T4 : Symbol(T4, Decl(mappedTypesGenericTuples.ts, 35, 79))
135+
>Readonly : Symbol(Readonly, Decl(lib.es5.d.ts, --, --))
136+
>L : Symbol(L, Decl(mappedTypesGenericTuples.ts, 36, 63))
137+
>L : Symbol(L, Decl(mappedTypesGenericTuples.ts, 36, 63))
138+
139+
// Repro from #56888
140+
141+
type R1<T> = readonly [...unknown[], T]; // readonly [...unknown[], T]
142+
>R1 : Symbol(R1, Decl(mappedTypesGenericTuples.ts, 36, 80))
143+
>T : Symbol(T, Decl(mappedTypesGenericTuples.ts, 40, 8))
144+
>T : Symbol(T, Decl(mappedTypesGenericTuples.ts, 40, 8))
145+
146+
type R2<T> = Readonly<[...unknown[], T]>; // readonly [...unknown[], T]
147+
>R2 : Symbol(R2, Decl(mappedTypesGenericTuples.ts, 40, 40))
148+
>T : Symbol(T, Decl(mappedTypesGenericTuples.ts, 41, 8))
149+
>Readonly : Symbol(Readonly, Decl(lib.es5.d.ts, --, --))
150+
>T : Symbol(T, Decl(mappedTypesGenericTuples.ts, 41, 8))
151+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
//// [tests/cases/conformance/types/mapped/mappedTypesGenericTuples.ts] ////
2+
3+
=== mappedTypesGenericTuples.ts ===
4+
// Property keys are `number` following the fixed part of a tuple
5+
6+
type K<T> = { [P in keyof T]: P };
7+
>K : K<T>
8+
9+
type M<T> = { [P in keyof T]: T[P] };
10+
>M : M<T>
11+
12+
type KA = K<[string, string, boolean]>; // ["0", "1", "2"]
13+
>KA : ["0", "1", "2"]
14+
15+
type KB = K<[string, string, ...string[], string]>; // ["0", "1", ...number[], number]
16+
>KB : ["0", "1", ...number[], number]
17+
18+
type KC = K<[...string[]]>; // number[]
19+
>KC : number[]
20+
21+
type KD = K<string[]>; // number[]
22+
>KD : number[]
23+
24+
type A = { a: string };
25+
>A : { a: string; }
26+
>a : string
27+
28+
type B = { b: string };
29+
>B : { b: string; }
30+
>b : string
31+
32+
type C = { c: string };
33+
>C : { c: string; }
34+
>c : string
35+
36+
type D = { d: string };
37+
>D : { d: string; }
38+
>d : string
39+
40+
type V0<T extends unknown[]> = [A, B?, ...T, ...C[]]
41+
>V0 : [A, (B | undefined)?, ...T, ...C[]]
42+
43+
type V1<T extends unknown[]> = [A, ...T, B, ...C[], D]
44+
>V1 : [A, ...T, B, ...C[], D]
45+
46+
type K0<T extends unknown[]> = K<V0<T>>; // ["0", "1"?, ...K<T>, ...number[]]
47+
>K0 : ["0", ("1" | undefined)?, ...K<T>, ...number[]]
48+
49+
type K1<T extends unknown[]> = K<V1<T>>; // ["0", ...K<T>, number, ...number[], number]
50+
>K1 : ["0", ...K<T>, number, ...number[], number]
51+
52+
type M0<T extends unknown[]> = M<V0<T>>; // [A, B?, ...M<T>, ...C[]]
53+
>M0 : [A, (B | undefined)?, ...M<T>, ...C[]]
54+
55+
type M1<T extends unknown[]> = M<V1<T>>; // [A, ...M<T>, B, ...C[], D]
56+
>M1 : [A, ...M<T>, B, ...C[], D]
57+
58+
// Repro from #48856
59+
60+
type Keys<O extends unknown[]> = { [K in keyof O]: K };
61+
>Keys : Keys<O>
62+
63+
type Keys1 = Keys<[string, ...string[]]>;
64+
>Keys1 : ["0", ...number[]]
65+
66+
type Keys2 = Keys<[string, ...string[], number]>;
67+
>Keys2 : ["0", ...number[], number]
68+
69+
// Repro from #56888
70+
71+
type T1 = ['a', 'b', 'c'] extends readonly [infer H, ...unknown[]] ? H : never; // "a"
72+
>T1 : "a"
73+
74+
type T2 = ['a', 'b', 'c'] extends Readonly<[infer H, ...unknown[]]> ? H : never; // "a"
75+
>T2 : "a"
76+
77+
type T3 = ['a', 'b', 'c'] extends readonly [...unknown[], infer L] ? L : never; // "c"
78+
>T3 : "c"
79+
80+
type T4 = ['a', 'b', 'c'] extends Readonly<[...unknown[], infer L]> ? L : never; // "c"
81+
>T4 : "c"
82+
83+
// Repro from #56888
84+
85+
type R1<T> = readonly [...unknown[], T]; // readonly [...unknown[], T]
86+
>R1 : R1<T>
87+
88+
type R2<T> = Readonly<[...unknown[], T]>; // readonly [...unknown[], T]
89+
>R2 : readonly [...unknown[], T]
90+

0 commit comments

Comments
 (0)