Skip to content

Commit

Permalink
Avoid creating rest elements with errorType when any is spread (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
Andarist committed Feb 16, 2024
1 parent c18c1c2 commit 29c0024
Show file tree
Hide file tree
Showing 13 changed files with 189 additions and 10 deletions.
5 changes: 4 additions & 1 deletion src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16883,7 +16883,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
const type = elementTypes[i];
const flags = target.elementFlags[i];
if (flags & ElementFlags.Variadic) {
if (type.flags & TypeFlags.InstantiableNonPrimitive || isGenericMappedType(type)) {
if (type.flags & TypeFlags.Any) {
addElement(type, ElementFlags.Rest, target.labeledElementDeclarations?.[i]);
}
else if (type.flags & TypeFlags.InstantiableNonPrimitive || isGenericMappedType(type)) {
// Generic variadic elements stay as they are.
addElement(type, ElementFlags.Variadic, target.labeledElementDeclarations?.[i]);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,10 @@ declare const itNum: Iterable<number>

;(function(a, ...rest) {})('', true, ...itNum)
>(function(a, ...rest) {})('', true, ...itNum) : void
>(function(a, ...rest) {}) : (a: string, rest_0: boolean, ...rest_1: any[]) => void
>function(a, ...rest) {} : (a: string, rest_0: boolean, ...rest_1: any[]) => void
>(function(a, ...rest) {}) : (a: string, rest_0: boolean, ...rest_1: Iterable<number>[]) => void
>function(a, ...rest) {} : (a: string, rest_0: boolean, ...rest_1: Iterable<number>[]) => void
>a : string
>rest : [boolean, ...any[]]
>rest : [boolean, ...Iterable<number>[]]
>'' : ""
>true : true
>...itNum : Iterable<number>
Expand Down Expand Up @@ -60,8 +60,8 @@ const res3 = fn1(true, ..."hello");
>"hello" : "hello"

const res4 = fn1(true, ...itNum);
>res4 : readonly [true, ...any[]]
>fn1(true, ...itNum) : readonly [true, ...any[]]
>res4 : readonly [true, ...Iterable<number>[]]
>fn1(true, ...itNum) : readonly [true, ...Iterable<number>[]]
>fn1 : <const T extends readonly unknown[]>(...args: T) => T
>true : true
>...itNum : Iterable<number>
Expand Down Expand Up @@ -95,8 +95,8 @@ const p3 = foo(true, ..."hello");
>"hello" : "hello"

const p4 = foo(true, ...itNum);
>p4 : [boolean, ...any[]]
>foo(true, ...itNum) : [boolean, ...any[]]
>p4 : [boolean, ...Iterable<number>[]]
>foo(true, ...itNum) : [boolean, ...Iterable<number>[]]
>foo : <T extends unknown[]>(...args: T) => T
>true : true
>...itNum : Iterable<number>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
//// [tests/cases/compiler/mappedTypeOverArrayWithBareAnyRestCanBeUsedAsRestParam1.ts] ////

=== mappedTypeOverArrayWithBareAnyRestCanBeUsedAsRestParam1.ts ===
// https://github.com/microsoft/TypeScript/issues/55932

type Replace<T extends [...any], A, B> = {
>Replace : Symbol(Replace, Decl(mappedTypeOverArrayWithBareAnyRestCanBeUsedAsRestParam1.ts, 0, 0))
>T : Symbol(T, Decl(mappedTypeOverArrayWithBareAnyRestCanBeUsedAsRestParam1.ts, 2, 13))
>A : Symbol(A, Decl(mappedTypeOverArrayWithBareAnyRestCanBeUsedAsRestParam1.ts, 2, 32))
>B : Symbol(B, Decl(mappedTypeOverArrayWithBareAnyRestCanBeUsedAsRestParam1.ts, 2, 35))

[K in keyof T]: T[K] extends A ? B : T[K];
>K : Symbol(K, Decl(mappedTypeOverArrayWithBareAnyRestCanBeUsedAsRestParam1.ts, 3, 3))
>T : Symbol(T, Decl(mappedTypeOverArrayWithBareAnyRestCanBeUsedAsRestParam1.ts, 2, 13))
>T : Symbol(T, Decl(mappedTypeOverArrayWithBareAnyRestCanBeUsedAsRestParam1.ts, 2, 13))
>K : Symbol(K, Decl(mappedTypeOverArrayWithBareAnyRestCanBeUsedAsRestParam1.ts, 3, 3))
>A : Symbol(A, Decl(mappedTypeOverArrayWithBareAnyRestCanBeUsedAsRestParam1.ts, 2, 32))
>B : Symbol(B, Decl(mappedTypeOverArrayWithBareAnyRestCanBeUsedAsRestParam1.ts, 2, 35))
>T : Symbol(T, Decl(mappedTypeOverArrayWithBareAnyRestCanBeUsedAsRestParam1.ts, 2, 13))
>K : Symbol(K, Decl(mappedTypeOverArrayWithBareAnyRestCanBeUsedAsRestParam1.ts, 3, 3))

};

type ReplaceParams1<ARRAY extends [...any], A, B> = (
>ReplaceParams1 : Symbol(ReplaceParams1, Decl(mappedTypeOverArrayWithBareAnyRestCanBeUsedAsRestParam1.ts, 4, 2))
>ARRAY : Symbol(ARRAY, Decl(mappedTypeOverArrayWithBareAnyRestCanBeUsedAsRestParam1.ts, 6, 20))
>A : Symbol(A, Decl(mappedTypeOverArrayWithBareAnyRestCanBeUsedAsRestParam1.ts, 6, 43))
>B : Symbol(B, Decl(mappedTypeOverArrayWithBareAnyRestCanBeUsedAsRestParam1.ts, 6, 46))

...args: Replace<ARRAY, A, B>
>args : Symbol(args, Decl(mappedTypeOverArrayWithBareAnyRestCanBeUsedAsRestParam1.ts, 6, 53))
>Replace : Symbol(Replace, Decl(mappedTypeOverArrayWithBareAnyRestCanBeUsedAsRestParam1.ts, 0, 0))
>ARRAY : Symbol(ARRAY, Decl(mappedTypeOverArrayWithBareAnyRestCanBeUsedAsRestParam1.ts, 6, 20))
>A : Symbol(A, Decl(mappedTypeOverArrayWithBareAnyRestCanBeUsedAsRestParam1.ts, 6, 43))
>B : Symbol(B, Decl(mappedTypeOverArrayWithBareAnyRestCanBeUsedAsRestParam1.ts, 6, 46))

) => any;

Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
//// [tests/cases/compiler/mappedTypeOverArrayWithBareAnyRestCanBeUsedAsRestParam1.ts] ////

=== mappedTypeOverArrayWithBareAnyRestCanBeUsedAsRestParam1.ts ===
// https://github.com/microsoft/TypeScript/issues/55932

type Replace<T extends [...any], A, B> = {
>Replace : Replace<T, A, B>

[K in keyof T]: T[K] extends A ? B : T[K];
};

type ReplaceParams1<ARRAY extends [...any], A, B> = (
>ReplaceParams1 : ReplaceParams1<ARRAY, A, B>

...args: Replace<ARRAY, A, B>
>args : Replace<ARRAY, A, B>

) => any;

36 changes: 36 additions & 0 deletions tests/baselines/reference/mappedTypesGenericTuples2.symbols
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
//// [tests/cases/conformance/types/mapped/mappedTypesGenericTuples2.ts] ////

=== mappedTypesGenericTuples2.ts ===
// https://github.com/microsoft/TypeScript/issues/57389

declare function getT<T>(): T;
>getT : Symbol(getT, Decl(mappedTypesGenericTuples2.ts, 0, 0))
>T : Symbol(T, Decl(mappedTypesGenericTuples2.ts, 2, 22))
>T : Symbol(T, Decl(mappedTypesGenericTuples2.ts, 2, 22))

Promise.all([getT<string>(), ...getT<any>()]).then((result) => {
>Promise.all([getT<string>(), ...getT<any>()]).then : Symbol(Promise.then, Decl(lib.es5.d.ts, --, --))
>Promise.all : Symbol(PromiseConstructor.all, Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --))
>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, --, --))
>all : Symbol(PromiseConstructor.all, Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --))
>getT : Symbol(getT, Decl(mappedTypesGenericTuples2.ts, 0, 0))
>getT : Symbol(getT, Decl(mappedTypesGenericTuples2.ts, 0, 0))
>then : Symbol(Promise.then, Decl(lib.es5.d.ts, --, --))
>result : Symbol(result, Decl(mappedTypesGenericTuples2.ts, 4, 52))

const head = result[0]; // string
>head : Symbol(head, Decl(mappedTypesGenericTuples2.ts, 5, 7))
>result : Symbol(result, Decl(mappedTypesGenericTuples2.ts, 4, 52))
>0 : Symbol(0)

const tail = result.slice(1); // any[]
>tail : Symbol(tail, Decl(mappedTypesGenericTuples2.ts, 6, 7))
>result.slice : Symbol(Array.slice, Decl(lib.es5.d.ts, --, --))
>result : Symbol(result, Decl(mappedTypesGenericTuples2.ts, 4, 52))
>slice : Symbol(Array.slice, Decl(lib.es5.d.ts, --, --))

tail satisfies string[]; // ok
>tail : Symbol(tail, Decl(mappedTypesGenericTuples2.ts, 6, 7))

});

45 changes: 45 additions & 0 deletions tests/baselines/reference/mappedTypesGenericTuples2.types
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
//// [tests/cases/conformance/types/mapped/mappedTypesGenericTuples2.ts] ////

=== mappedTypesGenericTuples2.ts ===
// https://github.com/microsoft/TypeScript/issues/57389

declare function getT<T>(): T;
>getT : <T>() => T

Promise.all([getT<string>(), ...getT<any>()]).then((result) => {
>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>
>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>
>Promise.all([getT<string>(), ...getT<any>()]) : Promise<[string, ...any[]]>
>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]>; }>; }
>Promise : PromiseConstructor
>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]>; }>; }
>[getT<string>(), ...getT<any>()] : [string, ...any[]]
>getT<string>() : string
>getT : <T>() => T
>...getT<any>() : any
>getT<any>() : any
>getT : <T>() => T
>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>
>(result) => { const head = result[0]; // string const tail = result.slice(1); // any[] tail satisfies string[]; // ok} : (result: [string, ...any[]]) => void
>result : [string, ...any[]]

const head = result[0]; // string
>head : string
>result[0] : string
>result : [string, ...any[]]
>0 : 0

const tail = result.slice(1); // any[]
>tail : any[]
>result.slice(1) : any[]
>result.slice : (start?: number | undefined, end?: number | undefined) => any[]
>result : [string, ...any[]]
>slice : (start?: number | undefined, end?: number | undefined) => any[]
>1 : 1

tail satisfies string[]; // ok
>tail satisfies string[] : any[]
>tail : any[]

});

2 changes: 2 additions & 0 deletions tests/baselines/reference/variadicTuples1.errors.txt
Original file line number Diff line number Diff line change
Expand Up @@ -540,4 +540,6 @@ variadicTuples1.ts(411,7): error TS2322: Type '[boolean, false]' is not assignab

type ToStringLength1<T extends any[]> = `${T['length']}`;
type ToStringLength2<T extends any[]> = `${[...T]['length']}`;

type AnyArr = [...any];

3 changes: 3 additions & 0 deletions tests/baselines/reference/variadicTuples1.js
Original file line number Diff line number Diff line change
Expand Up @@ -421,6 +421,8 @@ type U3 = [...[string, number], boolean];

type ToStringLength1<T extends any[]> = `${T['length']}`;
type ToStringLength2<T extends any[]> = `${[...T]['length']}`;

type AnyArr = [...any];


//// [variadicTuples1.js]
Expand Down Expand Up @@ -830,3 +832,4 @@ type U2 = [...[string, ...Numbers], boolean];
type U3 = [...[string, number], boolean];
type ToStringLength1<T extends any[]> = `${T['length']}`;
type ToStringLength2<T extends any[]> = `${[...T]['length']}`;
type AnyArr = [...any];
3 changes: 3 additions & 0 deletions tests/baselines/reference/variadicTuples1.symbols
Original file line number Diff line number Diff line change
Expand Up @@ -1416,3 +1416,6 @@ type ToStringLength2<T extends any[]> = `${[...T]['length']}`;
>T : Symbol(T, Decl(variadicTuples1.ts, 419, 21))
>T : Symbol(T, Decl(variadicTuples1.ts, 419, 21))

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

7 changes: 5 additions & 2 deletions tests/baselines/reference/variadicTuples1.types
Original file line number Diff line number Diff line change
Expand Up @@ -883,7 +883,7 @@ type T17 = DropFirst<[]>;
>T17 : unknown[]

type T18 = DropFirst<any>;
>T18 : unknown[] | any[]
>T18 : any[] | unknown[]

type T19 = DropFirst<never>;
>T19 : never
Expand Down Expand Up @@ -943,7 +943,7 @@ type T37 = DropLast<[]>; // unknown[], maybe should be []
>T37 : []

type T38 = DropLast<any>;
>T38 : unknown[] | any[]
>T38 : any[] | unknown[]

type T39 = DropLast<never>;
>T39 : never
Expand Down Expand Up @@ -1455,3 +1455,6 @@ type ToStringLength1<T extends any[]> = `${T['length']}`;
type ToStringLength2<T extends any[]> = `${[...T]['length']}`;
>ToStringLength2 : `${[...T]["length"]}`

type AnyArr = [...any];
>AnyArr : any[]

Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// @strict: true
// @noEmit: true

// https://github.com/microsoft/TypeScript/issues/55932

type Replace<T extends [...any], A, B> = {
[K in keyof T]: T[K] extends A ? B : T[K];
};

type ReplaceParams1<ARRAY extends [...any], A, B> = (
...args: Replace<ARRAY, A, B>
) => any;
13 changes: 13 additions & 0 deletions tests/cases/conformance/types/mapped/mappedTypesGenericTuples2.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// @strict: true
// @lib: esnext
// @noEmit: true

// https://github.com/microsoft/TypeScript/issues/57389

declare function getT<T>(): T;

Promise.all([getT<string>(), ...getT<any>()]).then((result) => {
const head = result[0]; // string
const tail = result.slice(1); // any[]
tail satisfies string[]; // ok
});
2 changes: 2 additions & 0 deletions tests/cases/conformance/types/tuple/variadicTuples1.ts
Original file line number Diff line number Diff line change
Expand Up @@ -421,3 +421,5 @@ type U3 = [...[string, number], boolean];

type ToStringLength1<T extends any[]> = `${T['length']}`;
type ToStringLength2<T extends any[]> = `${[...T]['length']}`;

type AnyArr = [...any];

0 comments on commit 29c0024

Please sign in to comment.