diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index ee074403b1b9f..2a721c69ce93f 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -26639,7 +26639,7 @@ namespace ts { function getNonArrayRestType(signature: Signature) { const restType = getEffectiveRestType(signature); - return restType && !isArrayType(restType) && !isTypeAny(restType) ? restType : undefined; + return restType && !isArrayType(restType) && !isTypeAny(restType) && (getReducedType(restType).flags & TypeFlags.Never) === 0 ? restType : undefined; } function getTypeOfFirstParameterOfSignature(signature: Signature) { @@ -29029,7 +29029,7 @@ namespace ts { // Only check rest parameter type if it's not a binding pattern. Since binding patterns are // not allowed in a rest parameter, we already have an error from checkGrammarParameterList. - if (node.dotDotDotToken && !isBindingPattern(node.name) && !isTypeAssignableTo(getTypeOfSymbol(node.symbol), anyReadonlyArrayType)) { + if (node.dotDotDotToken && !isBindingPattern(node.name) && !isTypeAssignableTo(getReducedType(getTypeOfSymbol(node.symbol)), anyReadonlyArrayType)) { error(node, Diagnostics.A_rest_parameter_must_be_of_an_array_type); } } diff --git a/tests/baselines/reference/genericRestTypes.errors.txt b/tests/baselines/reference/genericRestTypes.errors.txt new file mode 100644 index 0000000000000..c0fcb85e49201 --- /dev/null +++ b/tests/baselines/reference/genericRestTypes.errors.txt @@ -0,0 +1,39 @@ +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'. + Types of parameters 'cb' and 'cb' are incompatible. + Types of parameters 'args' and 'x' are incompatible. + Type '[string, ...T[number][]]' is not assignable to type 'never'. + + +==== tests/cases/compiler/genericRestTypes.ts (1 errors) ==== + // Repro from #25793 + + // Gets the parameters of a function type as a tuple + // Removes the first element from a tuple + type Tail = ((...args: T) => any) extends ((head: any, ...tail: infer U) => any) ? U : never; + + type MyFunctionType = (foo: number, bar: string) => boolean; + + type Explicit = (...args: Tail>) => ReturnType; // (bar: string) => boolean + + type Bind1 any> = (...args: Tail>) => ReturnType; + type Generic = Bind1; // (bar: string) => boolean + + function assignmentWithComplexRest() { + const fn1: (x: string, ...rest: T) => void = (x, ..._) => x; + const fn2: (...args: never) => void = fn1; + } + + function assignmentWithComplexRest2() { + const fn1: (cb: (x: string, ...rest: T) => void) => void = (cb) => {}; + const fn2: (cb: (...args: never) => void) => void = fn1; + ~~~ +!!! error TS2322: Type '(cb: (x: string, ...rest: T) => void) => void' is not assignable to type '(cb: (...args: never) => void) => void'. +!!! error TS2322: Types of parameters 'cb' and 'cb' are incompatible. +!!! error TS2322: Types of parameters 'args' and 'x' are incompatible. +!!! error TS2322: Type '[string, ...T[number][]]' is not assignable to type 'never'. + } + + function assignmentWithComplexRest3() { + const fn1: (x: string, ...rest: T) => void = (x, ..._) => x; + const fn2: (...args: {x: "a"} & {x: "b"}) => void = fn1; + } \ No newline at end of file diff --git a/tests/baselines/reference/genericRestTypes.js b/tests/baselines/reference/genericRestTypes.js index 5abf8113f388c..286e2aba1b73a 100644 --- a/tests/baselines/reference/genericRestTypes.js +++ b/tests/baselines/reference/genericRestTypes.js @@ -11,8 +11,46 @@ type Explicit = (...args: Tail>) => ReturnType any> = (...args: Tail>) => ReturnType; type Generic = Bind1; // (bar: string) => boolean - + +function assignmentWithComplexRest() { + const fn1: (x: string, ...rest: T) => void = (x, ..._) => x; + const fn2: (...args: never) => void = fn1; +} + +function assignmentWithComplexRest2() { + const fn1: (cb: (x: string, ...rest: T) => void) => void = (cb) => {}; + const fn2: (cb: (...args: never) => void) => void = fn1; +} + +function assignmentWithComplexRest3() { + const fn1: (x: string, ...rest: T) => void = (x, ..._) => x; + const fn2: (...args: {x: "a"} & {x: "b"}) => void = fn1; +} //// [genericRestTypes.js] "use strict"; // Repro from #25793 +function assignmentWithComplexRest() { + var fn1 = function (x) { + var _ = []; + for (var _i = 1; _i < arguments.length; _i++) { + _[_i - 1] = arguments[_i]; + } + return x; + }; + var fn2 = fn1; +} +function assignmentWithComplexRest2() { + var fn1 = function (cb) { }; + var fn2 = fn1; +} +function assignmentWithComplexRest3() { + var fn1 = function (x) { + var _ = []; + for (var _i = 1; _i < arguments.length; _i++) { + _[_i - 1] = arguments[_i]; + } + return x; + }; + var fn2 = fn1; +} diff --git a/tests/baselines/reference/genericRestTypes.symbols b/tests/baselines/reference/genericRestTypes.symbols index c8ab347609cb9..bd2545d9b9c2e 100644 --- a/tests/baselines/reference/genericRestTypes.symbols +++ b/tests/baselines/reference/genericRestTypes.symbols @@ -44,3 +44,61 @@ type Generic = Bind1; // (bar: string) => boolean >Bind1 : Symbol(Bind1, Decl(genericRestTypes.ts, 8, 90)) >MyFunctionType : Symbol(MyFunctionType, Decl(genericRestTypes.ts, 4, 110)) +function assignmentWithComplexRest() { +>assignmentWithComplexRest : Symbol(assignmentWithComplexRest, Decl(genericRestTypes.ts, 11, 37)) +>T : Symbol(T, Decl(genericRestTypes.ts, 13, 35)) + + const fn1: (x: string, ...rest: T) => void = (x, ..._) => x; +>fn1 : Symbol(fn1, Decl(genericRestTypes.ts, 14, 9)) +>x : Symbol(x, Decl(genericRestTypes.ts, 14, 16)) +>rest : Symbol(rest, Decl(genericRestTypes.ts, 14, 26)) +>T : Symbol(T, Decl(genericRestTypes.ts, 13, 35)) +>x : Symbol(x, Decl(genericRestTypes.ts, 14, 50)) +>_ : Symbol(_, Decl(genericRestTypes.ts, 14, 52)) +>x : Symbol(x, Decl(genericRestTypes.ts, 14, 50)) + + const fn2: (...args: never) => void = fn1; +>fn2 : Symbol(fn2, Decl(genericRestTypes.ts, 15, 9)) +>args : Symbol(args, Decl(genericRestTypes.ts, 15, 16)) +>fn1 : Symbol(fn1, Decl(genericRestTypes.ts, 14, 9)) +} + +function assignmentWithComplexRest2() { +>assignmentWithComplexRest2 : Symbol(assignmentWithComplexRest2, Decl(genericRestTypes.ts, 16, 1)) +>T : Symbol(T, Decl(genericRestTypes.ts, 18, 36)) + + const fn1: (cb: (x: string, ...rest: T) => void) => void = (cb) => {}; +>fn1 : Symbol(fn1, Decl(genericRestTypes.ts, 19, 9)) +>cb : Symbol(cb, Decl(genericRestTypes.ts, 19, 16)) +>x : Symbol(x, Decl(genericRestTypes.ts, 19, 21)) +>rest : Symbol(rest, Decl(genericRestTypes.ts, 19, 31)) +>T : Symbol(T, Decl(genericRestTypes.ts, 18, 36)) +>cb : Symbol(cb, Decl(genericRestTypes.ts, 19, 64)) + + const fn2: (cb: (...args: never) => void) => void = fn1; +>fn2 : Symbol(fn2, Decl(genericRestTypes.ts, 20, 9)) +>cb : Symbol(cb, Decl(genericRestTypes.ts, 20, 16)) +>args : Symbol(args, Decl(genericRestTypes.ts, 20, 21)) +>fn1 : Symbol(fn1, Decl(genericRestTypes.ts, 19, 9)) +} + +function assignmentWithComplexRest3() { +>assignmentWithComplexRest3 : Symbol(assignmentWithComplexRest3, Decl(genericRestTypes.ts, 21, 1)) +>T : Symbol(T, Decl(genericRestTypes.ts, 23, 36)) + + const fn1: (x: string, ...rest: T) => void = (x, ..._) => x; +>fn1 : Symbol(fn1, Decl(genericRestTypes.ts, 24, 9)) +>x : Symbol(x, Decl(genericRestTypes.ts, 24, 16)) +>rest : Symbol(rest, Decl(genericRestTypes.ts, 24, 26)) +>T : Symbol(T, Decl(genericRestTypes.ts, 23, 36)) +>x : Symbol(x, Decl(genericRestTypes.ts, 24, 50)) +>_ : Symbol(_, Decl(genericRestTypes.ts, 24, 52)) +>x : Symbol(x, Decl(genericRestTypes.ts, 24, 50)) + + const fn2: (...args: {x: "a"} & {x: "b"}) => void = fn1; +>fn2 : Symbol(fn2, Decl(genericRestTypes.ts, 25, 9)) +>args : Symbol(args, Decl(genericRestTypes.ts, 25, 16)) +>x : Symbol(x, Decl(genericRestTypes.ts, 25, 26)) +>x : Symbol(x, Decl(genericRestTypes.ts, 25, 37)) +>fn1 : Symbol(fn1, Decl(genericRestTypes.ts, 24, 9)) +} diff --git a/tests/baselines/reference/genericRestTypes.types b/tests/baselines/reference/genericRestTypes.types index b2fb37871bd23..78da48e79baf9 100644 --- a/tests/baselines/reference/genericRestTypes.types +++ b/tests/baselines/reference/genericRestTypes.types @@ -27,3 +27,58 @@ type Bind1 any> = (...args: Tail; // (bar: string) => boolean >Generic : Bind1 +function assignmentWithComplexRest() { +>assignmentWithComplexRest : () => void + + const fn1: (x: string, ...rest: T) => void = (x, ..._) => x; +>fn1 : (x: string, ...rest: T) => void +>x : string +>rest : T +>(x, ..._) => x : (x: string, ..._: T) => string +>x : string +>_ : T +>x : string + + const fn2: (...args: never) => void = fn1; +>fn2 : (...args: never) => void +>args : never +>fn1 : (x: string, ...rest: T) => void +} + +function assignmentWithComplexRest2() { +>assignmentWithComplexRest2 : () => void + + const fn1: (cb: (x: string, ...rest: T) => void) => void = (cb) => {}; +>fn1 : (cb: (x: string, ...rest: T) => void) => void +>cb : (x: string, ...rest: T) => void +>x : string +>rest : T +>(cb) => {} : (cb: (x: string, ...rest: T) => void) => void +>cb : (x: string, ...rest: T) => void + + const fn2: (cb: (...args: never) => void) => void = fn1; +>fn2 : (cb: (...args: never) => void) => void +>cb : (...args: never) => void +>args : never +>fn1 : (cb: (x: string, ...rest: T) => void) => void +} + +function assignmentWithComplexRest3() { +>assignmentWithComplexRest3 : () => void + + const fn1: (x: string, ...rest: T) => void = (x, ..._) => x; +>fn1 : (x: string, ...rest: T) => void +>x : string +>rest : T +>(x, ..._) => x : (x: string, ..._: T) => string +>x : string +>_ : T +>x : string + + const fn2: (...args: {x: "a"} & {x: "b"}) => void = fn1; +>fn2 : (...args: never) => void +>args : never +>x : "a" +>x : "b" +>fn1 : (x: string, ...rest: T) => void +} diff --git a/tests/cases/compiler/genericRestTypes.ts b/tests/cases/compiler/genericRestTypes.ts index 78eb9b53f7010..a8ecedeb070e9 100644 --- a/tests/cases/compiler/genericRestTypes.ts +++ b/tests/cases/compiler/genericRestTypes.ts @@ -12,3 +12,18 @@ type Explicit = (...args: Tail>) => ReturnType any> = (...args: Tail>) => ReturnType; type Generic = Bind1; // (bar: string) => boolean + +function assignmentWithComplexRest() { + const fn1: (x: string, ...rest: T) => void = (x, ..._) => x; + const fn2: (...args: never) => void = fn1; +} + +function assignmentWithComplexRest2() { + const fn1: (cb: (x: string, ...rest: T) => void) => void = (cb) => {}; + const fn2: (cb: (...args: never) => void) => void = fn1; +} + +function assignmentWithComplexRest3() { + const fn1: (x: string, ...rest: T) => void = (x, ..._) => x; + const fn2: (...args: {x: "a"} & {x: "b"}) => void = fn1; +} \ No newline at end of file