Skip to content

Commit 0e15b9f

Browse files
Make never rest type top-like (#35438)
* Make never rest type top-like * Add higher-order test * properly support types which reduce to never Co-authored-by: Wesley Wigham <[email protected]>
1 parent 2f0cc51 commit 0e15b9f

File tree

6 files changed

+208
-3
lines changed

6 files changed

+208
-3
lines changed

src/compiler/checker.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -26639,7 +26639,7 @@ namespace ts {
2663926639

2664026640
function getNonArrayRestType(signature: Signature) {
2664126641
const restType = getEffectiveRestType(signature);
26642-
return restType && !isArrayType(restType) && !isTypeAny(restType) ? restType : undefined;
26642+
return restType && !isArrayType(restType) && !isTypeAny(restType) && (getReducedType(restType).flags & TypeFlags.Never) === 0 ? restType : undefined;
2664326643
}
2664426644

2664526645
function getTypeOfFirstParameterOfSignature(signature: Signature) {
@@ -29029,7 +29029,7 @@ namespace ts {
2902929029

2903029030
// Only check rest parameter type if it's not a binding pattern. Since binding patterns are
2903129031
// not allowed in a rest parameter, we already have an error from checkGrammarParameterList.
29032-
if (node.dotDotDotToken && !isBindingPattern(node.name) && !isTypeAssignableTo(getTypeOfSymbol(node.symbol), anyReadonlyArrayType)) {
29032+
if (node.dotDotDotToken && !isBindingPattern(node.name) && !isTypeAssignableTo(getReducedType(getTypeOfSymbol(node.symbol)), anyReadonlyArrayType)) {
2903329033
error(node, Diagnostics.A_rest_parameter_must_be_of_an_array_type);
2903429034
}
2903529035
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
tests/cases/compiler/genericRestTypes.ts(21,11): error TS2322: Type '(cb: (x: string, ...rest: T) => void) => void' is not assignable to type '(cb: (...args: never) => void) => void'.
2+
Types of parameters 'cb' and 'cb' are incompatible.
3+
Types of parameters 'args' and 'x' are incompatible.
4+
Type '[string, ...T[number][]]' is not assignable to type 'never'.
5+
6+
7+
==== tests/cases/compiler/genericRestTypes.ts (1 errors) ====
8+
// Repro from #25793
9+
10+
// Gets the parameters of a function type as a tuple
11+
// Removes the first element from a tuple
12+
type Tail<T extends any[]> = ((...args: T) => any) extends ((head: any, ...tail: infer U) => any) ? U : never;
13+
14+
type MyFunctionType = (foo: number, bar: string) => boolean;
15+
16+
type Explicit = (...args: Tail<Parameters<MyFunctionType>>) => ReturnType<MyFunctionType>; // (bar: string) => boolean
17+
18+
type Bind1<T extends (head: any, ...tail: any[]) => any> = (...args: Tail<Parameters<T>>) => ReturnType<T>;
19+
type Generic = Bind1<MyFunctionType>; // (bar: string) => boolean
20+
21+
function assignmentWithComplexRest<T extends any[]>() {
22+
const fn1: (x: string, ...rest: T) => void = (x, ..._) => x;
23+
const fn2: (...args: never) => void = fn1;
24+
}
25+
26+
function assignmentWithComplexRest2<T extends any[]>() {
27+
const fn1: (cb: (x: string, ...rest: T) => void) => void = (cb) => {};
28+
const fn2: (cb: (...args: never) => void) => void = fn1;
29+
~~~
30+
!!! error TS2322: Type '(cb: (x: string, ...rest: T) => void) => void' is not assignable to type '(cb: (...args: never) => void) => void'.
31+
!!! error TS2322: Types of parameters 'cb' and 'cb' are incompatible.
32+
!!! error TS2322: Types of parameters 'args' and 'x' are incompatible.
33+
!!! error TS2322: Type '[string, ...T[number][]]' is not assignable to type 'never'.
34+
}
35+
36+
function assignmentWithComplexRest3<T extends any[]>() {
37+
const fn1: (x: string, ...rest: T) => void = (x, ..._) => x;
38+
const fn2: (...args: {x: "a"} & {x: "b"}) => void = fn1;
39+
}

tests/baselines/reference/genericRestTypes.js

+39-1
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,46 @@ type Explicit = (...args: Tail<Parameters<MyFunctionType>>) => ReturnType<MyFunc
1111

1212
type Bind1<T extends (head: any, ...tail: any[]) => any> = (...args: Tail<Parameters<T>>) => ReturnType<T>;
1313
type Generic = Bind1<MyFunctionType>; // (bar: string) => boolean
14-
14+
15+
function assignmentWithComplexRest<T extends any[]>() {
16+
const fn1: (x: string, ...rest: T) => void = (x, ..._) => x;
17+
const fn2: (...args: never) => void = fn1;
18+
}
19+
20+
function assignmentWithComplexRest2<T extends any[]>() {
21+
const fn1: (cb: (x: string, ...rest: T) => void) => void = (cb) => {};
22+
const fn2: (cb: (...args: never) => void) => void = fn1;
23+
}
24+
25+
function assignmentWithComplexRest3<T extends any[]>() {
26+
const fn1: (x: string, ...rest: T) => void = (x, ..._) => x;
27+
const fn2: (...args: {x: "a"} & {x: "b"}) => void = fn1;
28+
}
1529

1630
//// [genericRestTypes.js]
1731
"use strict";
1832
// Repro from #25793
33+
function assignmentWithComplexRest() {
34+
var fn1 = function (x) {
35+
var _ = [];
36+
for (var _i = 1; _i < arguments.length; _i++) {
37+
_[_i - 1] = arguments[_i];
38+
}
39+
return x;
40+
};
41+
var fn2 = fn1;
42+
}
43+
function assignmentWithComplexRest2() {
44+
var fn1 = function (cb) { };
45+
var fn2 = fn1;
46+
}
47+
function assignmentWithComplexRest3() {
48+
var fn1 = function (x) {
49+
var _ = [];
50+
for (var _i = 1; _i < arguments.length; _i++) {
51+
_[_i - 1] = arguments[_i];
52+
}
53+
return x;
54+
};
55+
var fn2 = fn1;
56+
}

tests/baselines/reference/genericRestTypes.symbols

+58
Original file line numberDiff line numberDiff line change
@@ -44,3 +44,61 @@ type Generic = Bind1<MyFunctionType>; // (bar: string) => boolean
4444
>Bind1 : Symbol(Bind1, Decl(genericRestTypes.ts, 8, 90))
4545
>MyFunctionType : Symbol(MyFunctionType, Decl(genericRestTypes.ts, 4, 110))
4646

47+
function assignmentWithComplexRest<T extends any[]>() {
48+
>assignmentWithComplexRest : Symbol(assignmentWithComplexRest, Decl(genericRestTypes.ts, 11, 37))
49+
>T : Symbol(T, Decl(genericRestTypes.ts, 13, 35))
50+
51+
const fn1: (x: string, ...rest: T) => void = (x, ..._) => x;
52+
>fn1 : Symbol(fn1, Decl(genericRestTypes.ts, 14, 9))
53+
>x : Symbol(x, Decl(genericRestTypes.ts, 14, 16))
54+
>rest : Symbol(rest, Decl(genericRestTypes.ts, 14, 26))
55+
>T : Symbol(T, Decl(genericRestTypes.ts, 13, 35))
56+
>x : Symbol(x, Decl(genericRestTypes.ts, 14, 50))
57+
>_ : Symbol(_, Decl(genericRestTypes.ts, 14, 52))
58+
>x : Symbol(x, Decl(genericRestTypes.ts, 14, 50))
59+
60+
const fn2: (...args: never) => void = fn1;
61+
>fn2 : Symbol(fn2, Decl(genericRestTypes.ts, 15, 9))
62+
>args : Symbol(args, Decl(genericRestTypes.ts, 15, 16))
63+
>fn1 : Symbol(fn1, Decl(genericRestTypes.ts, 14, 9))
64+
}
65+
66+
function assignmentWithComplexRest2<T extends any[]>() {
67+
>assignmentWithComplexRest2 : Symbol(assignmentWithComplexRest2, Decl(genericRestTypes.ts, 16, 1))
68+
>T : Symbol(T, Decl(genericRestTypes.ts, 18, 36))
69+
70+
const fn1: (cb: (x: string, ...rest: T) => void) => void = (cb) => {};
71+
>fn1 : Symbol(fn1, Decl(genericRestTypes.ts, 19, 9))
72+
>cb : Symbol(cb, Decl(genericRestTypes.ts, 19, 16))
73+
>x : Symbol(x, Decl(genericRestTypes.ts, 19, 21))
74+
>rest : Symbol(rest, Decl(genericRestTypes.ts, 19, 31))
75+
>T : Symbol(T, Decl(genericRestTypes.ts, 18, 36))
76+
>cb : Symbol(cb, Decl(genericRestTypes.ts, 19, 64))
77+
78+
const fn2: (cb: (...args: never) => void) => void = fn1;
79+
>fn2 : Symbol(fn2, Decl(genericRestTypes.ts, 20, 9))
80+
>cb : Symbol(cb, Decl(genericRestTypes.ts, 20, 16))
81+
>args : Symbol(args, Decl(genericRestTypes.ts, 20, 21))
82+
>fn1 : Symbol(fn1, Decl(genericRestTypes.ts, 19, 9))
83+
}
84+
85+
function assignmentWithComplexRest3<T extends any[]>() {
86+
>assignmentWithComplexRest3 : Symbol(assignmentWithComplexRest3, Decl(genericRestTypes.ts, 21, 1))
87+
>T : Symbol(T, Decl(genericRestTypes.ts, 23, 36))
88+
89+
const fn1: (x: string, ...rest: T) => void = (x, ..._) => x;
90+
>fn1 : Symbol(fn1, Decl(genericRestTypes.ts, 24, 9))
91+
>x : Symbol(x, Decl(genericRestTypes.ts, 24, 16))
92+
>rest : Symbol(rest, Decl(genericRestTypes.ts, 24, 26))
93+
>T : Symbol(T, Decl(genericRestTypes.ts, 23, 36))
94+
>x : Symbol(x, Decl(genericRestTypes.ts, 24, 50))
95+
>_ : Symbol(_, Decl(genericRestTypes.ts, 24, 52))
96+
>x : Symbol(x, Decl(genericRestTypes.ts, 24, 50))
97+
98+
const fn2: (...args: {x: "a"} & {x: "b"}) => void = fn1;
99+
>fn2 : Symbol(fn2, Decl(genericRestTypes.ts, 25, 9))
100+
>args : Symbol(args, Decl(genericRestTypes.ts, 25, 16))
101+
>x : Symbol(x, Decl(genericRestTypes.ts, 25, 26))
102+
>x : Symbol(x, Decl(genericRestTypes.ts, 25, 37))
103+
>fn1 : Symbol(fn1, Decl(genericRestTypes.ts, 24, 9))
104+
}

tests/baselines/reference/genericRestTypes.types

+55
Original file line numberDiff line numberDiff line change
@@ -27,3 +27,58 @@ type Bind1<T extends (head: any, ...tail: any[]) => any> = (...args: Tail<Parame
2727
type Generic = Bind1<MyFunctionType>; // (bar: string) => boolean
2828
>Generic : Bind1<MyFunctionType>
2929

30+
function assignmentWithComplexRest<T extends any[]>() {
31+
>assignmentWithComplexRest : <T extends any[]>() => void
32+
33+
const fn1: (x: string, ...rest: T) => void = (x, ..._) => x;
34+
>fn1 : (x: string, ...rest: T) => void
35+
>x : string
36+
>rest : T
37+
>(x, ..._) => x : (x: string, ..._: T) => string
38+
>x : string
39+
>_ : T
40+
>x : string
41+
42+
const fn2: (...args: never) => void = fn1;
43+
>fn2 : (...args: never) => void
44+
>args : never
45+
>fn1 : (x: string, ...rest: T) => void
46+
}
47+
48+
function assignmentWithComplexRest2<T extends any[]>() {
49+
>assignmentWithComplexRest2 : <T extends any[]>() => void
50+
51+
const fn1: (cb: (x: string, ...rest: T) => void) => void = (cb) => {};
52+
>fn1 : (cb: (x: string, ...rest: T) => void) => void
53+
>cb : (x: string, ...rest: T) => void
54+
>x : string
55+
>rest : T
56+
>(cb) => {} : (cb: (x: string, ...rest: T) => void) => void
57+
>cb : (x: string, ...rest: T) => void
58+
59+
const fn2: (cb: (...args: never) => void) => void = fn1;
60+
>fn2 : (cb: (...args: never) => void) => void
61+
>cb : (...args: never) => void
62+
>args : never
63+
>fn1 : (cb: (x: string, ...rest: T) => void) => void
64+
}
65+
66+
function assignmentWithComplexRest3<T extends any[]>() {
67+
>assignmentWithComplexRest3 : <T extends any[]>() => void
68+
69+
const fn1: (x: string, ...rest: T) => void = (x, ..._) => x;
70+
>fn1 : (x: string, ...rest: T) => void
71+
>x : string
72+
>rest : T
73+
>(x, ..._) => x : (x: string, ..._: T) => string
74+
>x : string
75+
>_ : T
76+
>x : string
77+
78+
const fn2: (...args: {x: "a"} & {x: "b"}) => void = fn1;
79+
>fn2 : (...args: never) => void
80+
>args : never
81+
>x : "a"
82+
>x : "b"
83+
>fn1 : (x: string, ...rest: T) => void
84+
}

tests/cases/compiler/genericRestTypes.ts

+15
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,18 @@ type Explicit = (...args: Tail<Parameters<MyFunctionType>>) => ReturnType<MyFunc
1212

1313
type Bind1<T extends (head: any, ...tail: any[]) => any> = (...args: Tail<Parameters<T>>) => ReturnType<T>;
1414
type Generic = Bind1<MyFunctionType>; // (bar: string) => boolean
15+
16+
function assignmentWithComplexRest<T extends any[]>() {
17+
const fn1: (x: string, ...rest: T) => void = (x, ..._) => x;
18+
const fn2: (...args: never) => void = fn1;
19+
}
20+
21+
function assignmentWithComplexRest2<T extends any[]>() {
22+
const fn1: (cb: (x: string, ...rest: T) => void) => void = (cb) => {};
23+
const fn2: (cb: (...args: never) => void) => void = fn1;
24+
}
25+
26+
function assignmentWithComplexRest3<T extends any[]>() {
27+
const fn1: (x: string, ...rest: T) => void = (x, ..._) => x;
28+
const fn2: (...args: {x: "a"} & {x: "b"}) => void = fn1;
29+
}

0 commit comments

Comments
 (0)