Skip to content

Commit 29c0024

Browse files
authored
Avoid creating rest elements with errorType when any is spread (#57116)
1 parent c18c1c2 commit 29c0024

13 files changed

+189
-10
lines changed

src/compiler/checker.ts

+4-1
Original file line numberDiff line numberDiff line change
@@ -16883,7 +16883,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
1688316883
const type = elementTypes[i];
1688416884
const flags = target.elementFlags[i];
1688516885
if (flags & ElementFlags.Variadic) {
16886-
if (type.flags & TypeFlags.InstantiableNonPrimitive || isGenericMappedType(type)) {
16886+
if (type.flags & TypeFlags.Any) {
16887+
addElement(type, ElementFlags.Rest, target.labeledElementDeclarations?.[i]);
16888+
}
16889+
else if (type.flags & TypeFlags.InstantiableNonPrimitive || isGenericMappedType(type)) {
1688716890
// Generic variadic elements stay as they are.
1688816891
addElement(type, ElementFlags.Variadic, target.labeledElementDeclarations?.[i]);
1688916892
}

tests/baselines/reference/argumentsSpreadRestIterables(target=es5).types

+7-7
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,10 @@ declare const itNum: Iterable<number>
2424

2525
;(function(a, ...rest) {})('', true, ...itNum)
2626
>(function(a, ...rest) {})('', true, ...itNum) : void
27-
>(function(a, ...rest) {}) : (a: string, rest_0: boolean, ...rest_1: any[]) => void
28-
>function(a, ...rest) {} : (a: string, rest_0: boolean, ...rest_1: any[]) => void
27+
>(function(a, ...rest) {}) : (a: string, rest_0: boolean, ...rest_1: Iterable<number>[]) => void
28+
>function(a, ...rest) {} : (a: string, rest_0: boolean, ...rest_1: Iterable<number>[]) => void
2929
>a : string
30-
>rest : [boolean, ...any[]]
30+
>rest : [boolean, ...Iterable<number>[]]
3131
>'' : ""
3232
>true : true
3333
>...itNum : Iterable<number>
@@ -60,8 +60,8 @@ const res3 = fn1(true, ..."hello");
6060
>"hello" : "hello"
6161

6262
const res4 = fn1(true, ...itNum);
63-
>res4 : readonly [true, ...any[]]
64-
>fn1(true, ...itNum) : readonly [true, ...any[]]
63+
>res4 : readonly [true, ...Iterable<number>[]]
64+
>fn1(true, ...itNum) : readonly [true, ...Iterable<number>[]]
6565
>fn1 : <const T extends readonly unknown[]>(...args: T) => T
6666
>true : true
6767
>...itNum : Iterable<number>
@@ -95,8 +95,8 @@ const p3 = foo(true, ..."hello");
9595
>"hello" : "hello"
9696

9797
const p4 = foo(true, ...itNum);
98-
>p4 : [boolean, ...any[]]
99-
>foo(true, ...itNum) : [boolean, ...any[]]
98+
>p4 : [boolean, ...Iterable<number>[]]
99+
>foo(true, ...itNum) : [boolean, ...Iterable<number>[]]
100100
>foo : <T extends unknown[]>(...args: T) => T
101101
>true : true
102102
>...itNum : Iterable<number>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
//// [tests/cases/compiler/mappedTypeOverArrayWithBareAnyRestCanBeUsedAsRestParam1.ts] ////
2+
3+
=== mappedTypeOverArrayWithBareAnyRestCanBeUsedAsRestParam1.ts ===
4+
// https://github.com/microsoft/TypeScript/issues/55932
5+
6+
type Replace<T extends [...any], A, B> = {
7+
>Replace : Symbol(Replace, Decl(mappedTypeOverArrayWithBareAnyRestCanBeUsedAsRestParam1.ts, 0, 0))
8+
>T : Symbol(T, Decl(mappedTypeOverArrayWithBareAnyRestCanBeUsedAsRestParam1.ts, 2, 13))
9+
>A : Symbol(A, Decl(mappedTypeOverArrayWithBareAnyRestCanBeUsedAsRestParam1.ts, 2, 32))
10+
>B : Symbol(B, Decl(mappedTypeOverArrayWithBareAnyRestCanBeUsedAsRestParam1.ts, 2, 35))
11+
12+
[K in keyof T]: T[K] extends A ? B : T[K];
13+
>K : Symbol(K, Decl(mappedTypeOverArrayWithBareAnyRestCanBeUsedAsRestParam1.ts, 3, 3))
14+
>T : Symbol(T, Decl(mappedTypeOverArrayWithBareAnyRestCanBeUsedAsRestParam1.ts, 2, 13))
15+
>T : Symbol(T, Decl(mappedTypeOverArrayWithBareAnyRestCanBeUsedAsRestParam1.ts, 2, 13))
16+
>K : Symbol(K, Decl(mappedTypeOverArrayWithBareAnyRestCanBeUsedAsRestParam1.ts, 3, 3))
17+
>A : Symbol(A, Decl(mappedTypeOverArrayWithBareAnyRestCanBeUsedAsRestParam1.ts, 2, 32))
18+
>B : Symbol(B, Decl(mappedTypeOverArrayWithBareAnyRestCanBeUsedAsRestParam1.ts, 2, 35))
19+
>T : Symbol(T, Decl(mappedTypeOverArrayWithBareAnyRestCanBeUsedAsRestParam1.ts, 2, 13))
20+
>K : Symbol(K, Decl(mappedTypeOverArrayWithBareAnyRestCanBeUsedAsRestParam1.ts, 3, 3))
21+
22+
};
23+
24+
type ReplaceParams1<ARRAY extends [...any], A, B> = (
25+
>ReplaceParams1 : Symbol(ReplaceParams1, Decl(mappedTypeOverArrayWithBareAnyRestCanBeUsedAsRestParam1.ts, 4, 2))
26+
>ARRAY : Symbol(ARRAY, Decl(mappedTypeOverArrayWithBareAnyRestCanBeUsedAsRestParam1.ts, 6, 20))
27+
>A : Symbol(A, Decl(mappedTypeOverArrayWithBareAnyRestCanBeUsedAsRestParam1.ts, 6, 43))
28+
>B : Symbol(B, Decl(mappedTypeOverArrayWithBareAnyRestCanBeUsedAsRestParam1.ts, 6, 46))
29+
30+
...args: Replace<ARRAY, A, B>
31+
>args : Symbol(args, Decl(mappedTypeOverArrayWithBareAnyRestCanBeUsedAsRestParam1.ts, 6, 53))
32+
>Replace : Symbol(Replace, Decl(mappedTypeOverArrayWithBareAnyRestCanBeUsedAsRestParam1.ts, 0, 0))
33+
>ARRAY : Symbol(ARRAY, Decl(mappedTypeOverArrayWithBareAnyRestCanBeUsedAsRestParam1.ts, 6, 20))
34+
>A : Symbol(A, Decl(mappedTypeOverArrayWithBareAnyRestCanBeUsedAsRestParam1.ts, 6, 43))
35+
>B : Symbol(B, Decl(mappedTypeOverArrayWithBareAnyRestCanBeUsedAsRestParam1.ts, 6, 46))
36+
37+
) => any;
38+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
//// [tests/cases/compiler/mappedTypeOverArrayWithBareAnyRestCanBeUsedAsRestParam1.ts] ////
2+
3+
=== mappedTypeOverArrayWithBareAnyRestCanBeUsedAsRestParam1.ts ===
4+
// https://github.com/microsoft/TypeScript/issues/55932
5+
6+
type Replace<T extends [...any], A, B> = {
7+
>Replace : Replace<T, A, B>
8+
9+
[K in keyof T]: T[K] extends A ? B : T[K];
10+
};
11+
12+
type ReplaceParams1<ARRAY extends [...any], A, B> = (
13+
>ReplaceParams1 : ReplaceParams1<ARRAY, A, B>
14+
15+
...args: Replace<ARRAY, A, B>
16+
>args : Replace<ARRAY, A, B>
17+
18+
) => any;
19+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
//// [tests/cases/conformance/types/mapped/mappedTypesGenericTuples2.ts] ////
2+
3+
=== mappedTypesGenericTuples2.ts ===
4+
// https://github.com/microsoft/TypeScript/issues/57389
5+
6+
declare function getT<T>(): T;
7+
>getT : Symbol(getT, Decl(mappedTypesGenericTuples2.ts, 0, 0))
8+
>T : Symbol(T, Decl(mappedTypesGenericTuples2.ts, 2, 22))
9+
>T : Symbol(T, Decl(mappedTypesGenericTuples2.ts, 2, 22))
10+
11+
Promise.all([getT<string>(), ...getT<any>()]).then((result) => {
12+
>Promise.all([getT<string>(), ...getT<any>()]).then : Symbol(Promise.then, Decl(lib.es5.d.ts, --, --))
13+
>Promise.all : Symbol(PromiseConstructor.all, Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --))
14+
>Promise : Symbol(Promise, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2018.promise.d.ts, --, --))
15+
>all : Symbol(PromiseConstructor.all, Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --))
16+
>getT : Symbol(getT, Decl(mappedTypesGenericTuples2.ts, 0, 0))
17+
>getT : Symbol(getT, Decl(mappedTypesGenericTuples2.ts, 0, 0))
18+
>then : Symbol(Promise.then, Decl(lib.es5.d.ts, --, --))
19+
>result : Symbol(result, Decl(mappedTypesGenericTuples2.ts, 4, 52))
20+
21+
const head = result[0]; // string
22+
>head : Symbol(head, Decl(mappedTypesGenericTuples2.ts, 5, 7))
23+
>result : Symbol(result, Decl(mappedTypesGenericTuples2.ts, 4, 52))
24+
>0 : Symbol(0)
25+
26+
const tail = result.slice(1); // any[]
27+
>tail : Symbol(tail, Decl(mappedTypesGenericTuples2.ts, 6, 7))
28+
>result.slice : Symbol(Array.slice, Decl(lib.es5.d.ts, --, --))
29+
>result : Symbol(result, Decl(mappedTypesGenericTuples2.ts, 4, 52))
30+
>slice : Symbol(Array.slice, Decl(lib.es5.d.ts, --, --))
31+
32+
tail satisfies string[]; // ok
33+
>tail : Symbol(tail, Decl(mappedTypesGenericTuples2.ts, 6, 7))
34+
35+
});
36+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
//// [tests/cases/conformance/types/mapped/mappedTypesGenericTuples2.ts] ////
2+
3+
=== mappedTypesGenericTuples2.ts ===
4+
// https://github.com/microsoft/TypeScript/issues/57389
5+
6+
declare function getT<T>(): T;
7+
>getT : <T>() => T
8+
9+
Promise.all([getT<string>(), ...getT<any>()]).then((result) => {
10+
>Promise.all([getT<string>(), ...getT<any>()]).then((result) => { const head = result[0]; // string const tail = result.slice(1); // any[] tail satisfies string[]; // ok}) : Promise<void>
11+
>Promise.all([getT<string>(), ...getT<any>()]).then : <TResult1 = [string, ...any[]], TResult2 = never>(onfulfilled?: ((value: [string, ...any[]]) => TResult1 | PromiseLike<TResult1>) | null | undefined, onrejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | null | undefined) => Promise<TResult1 | TResult2>
12+
>Promise.all([getT<string>(), ...getT<any>()]) : Promise<[string, ...any[]]>
13+
>Promise.all : { <T>(values: Iterable<T | PromiseLike<T>>): Promise<Awaited<T>[]>; <T_1 extends readonly unknown[] | []>(values: T_1): Promise<{ -readonly [P in keyof T_1]: Awaited<T_1[P]>; }>; }
14+
>Promise : PromiseConstructor
15+
>all : { <T>(values: Iterable<T | PromiseLike<T>>): Promise<Awaited<T>[]>; <T_1 extends readonly unknown[] | []>(values: T_1): Promise<{ -readonly [P in keyof T_1]: Awaited<T_1[P]>; }>; }
16+
>[getT<string>(), ...getT<any>()] : [string, ...any[]]
17+
>getT<string>() : string
18+
>getT : <T>() => T
19+
>...getT<any>() : any
20+
>getT<any>() : any
21+
>getT : <T>() => T
22+
>then : <TResult1 = [string, ...any[]], TResult2 = never>(onfulfilled?: ((value: [string, ...any[]]) => TResult1 | PromiseLike<TResult1>) | null | undefined, onrejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | null | undefined) => Promise<TResult1 | TResult2>
23+
>(result) => { const head = result[0]; // string const tail = result.slice(1); // any[] tail satisfies string[]; // ok} : (result: [string, ...any[]]) => void
24+
>result : [string, ...any[]]
25+
26+
const head = result[0]; // string
27+
>head : string
28+
>result[0] : string
29+
>result : [string, ...any[]]
30+
>0 : 0
31+
32+
const tail = result.slice(1); // any[]
33+
>tail : any[]
34+
>result.slice(1) : any[]
35+
>result.slice : (start?: number | undefined, end?: number | undefined) => any[]
36+
>result : [string, ...any[]]
37+
>slice : (start?: number | undefined, end?: number | undefined) => any[]
38+
>1 : 1
39+
40+
tail satisfies string[]; // ok
41+
>tail satisfies string[] : any[]
42+
>tail : any[]
43+
44+
});
45+

tests/baselines/reference/variadicTuples1.errors.txt

+2
Original file line numberDiff line numberDiff line change
@@ -540,4 +540,6 @@ variadicTuples1.ts(411,7): error TS2322: Type '[boolean, false]' is not assignab
540540

541541
type ToStringLength1<T extends any[]> = `${T['length']}`;
542542
type ToStringLength2<T extends any[]> = `${[...T]['length']}`;
543+
544+
type AnyArr = [...any];
543545

tests/baselines/reference/variadicTuples1.js

+3
Original file line numberDiff line numberDiff line change
@@ -421,6 +421,8 @@ type U3 = [...[string, number], boolean];
421421

422422
type ToStringLength1<T extends any[]> = `${T['length']}`;
423423
type ToStringLength2<T extends any[]> = `${[...T]['length']}`;
424+
425+
type AnyArr = [...any];
424426

425427

426428
//// [variadicTuples1.js]
@@ -830,3 +832,4 @@ type U2 = [...[string, ...Numbers], boolean];
830832
type U3 = [...[string, number], boolean];
831833
type ToStringLength1<T extends any[]> = `${T['length']}`;
832834
type ToStringLength2<T extends any[]> = `${[...T]['length']}`;
835+
type AnyArr = [...any];

tests/baselines/reference/variadicTuples1.symbols

+3
Original file line numberDiff line numberDiff line change
@@ -1416,3 +1416,6 @@ type ToStringLength2<T extends any[]> = `${[...T]['length']}`;
14161416
>T : Symbol(T, Decl(variadicTuples1.ts, 419, 21))
14171417
>T : Symbol(T, Decl(variadicTuples1.ts, 419, 21))
14181418

1419+
type AnyArr = [...any];
1420+
>AnyArr : Symbol(AnyArr, Decl(variadicTuples1.ts, 419, 62))
1421+

tests/baselines/reference/variadicTuples1.types

+5-2
Original file line numberDiff line numberDiff line change
@@ -883,7 +883,7 @@ type T17 = DropFirst<[]>;
883883
>T17 : unknown[]
884884

885885
type T18 = DropFirst<any>;
886-
>T18 : unknown[] | any[]
886+
>T18 : any[] | unknown[]
887887

888888
type T19 = DropFirst<never>;
889889
>T19 : never
@@ -943,7 +943,7 @@ type T37 = DropLast<[]>; // unknown[], maybe should be []
943943
>T37 : []
944944

945945
type T38 = DropLast<any>;
946-
>T38 : unknown[] | any[]
946+
>T38 : any[] | unknown[]
947947

948948
type T39 = DropLast<never>;
949949
>T39 : never
@@ -1455,3 +1455,6 @@ type ToStringLength1<T extends any[]> = `${T['length']}`;
14551455
type ToStringLength2<T extends any[]> = `${[...T]['length']}`;
14561456
>ToStringLength2 : `${[...T]["length"]}`
14571457

1458+
type AnyArr = [...any];
1459+
>AnyArr : any[]
1460+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// @strict: true
2+
// @noEmit: true
3+
4+
// https://github.com/microsoft/TypeScript/issues/55932
5+
6+
type Replace<T extends [...any], A, B> = {
7+
[K in keyof T]: T[K] extends A ? B : T[K];
8+
};
9+
10+
type ReplaceParams1<ARRAY extends [...any], A, B> = (
11+
...args: Replace<ARRAY, A, B>
12+
) => any;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// @strict: true
2+
// @lib: esnext
3+
// @noEmit: true
4+
5+
// https://github.com/microsoft/TypeScript/issues/57389
6+
7+
declare function getT<T>(): T;
8+
9+
Promise.all([getT<string>(), ...getT<any>()]).then((result) => {
10+
const head = result[0]; // string
11+
const tail = result.slice(1); // any[]
12+
tail satisfies string[]; // ok
13+
});

tests/cases/conformance/types/tuple/variadicTuples1.ts

+2
Original file line numberDiff line numberDiff line change
@@ -421,3 +421,5 @@ type U3 = [...[string, number], boolean];
421421

422422
type ToStringLength1<T extends any[]> = `${T['length']}`;
423423
type ToStringLength2<T extends any[]> = `${[...T]['length']}`;
424+
425+
type AnyArr = [...any];

0 commit comments

Comments
 (0)