Skip to content

Commit 4d70d70

Browse files
committed
fix(checker): allow unknown[] as valid mixin constructor rest param type
1 parent 7b8cb3b commit 4d70d70

6 files changed

Lines changed: 178 additions & 1 deletion

File tree

src/compiler/checker.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13161,7 +13161,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
1316113161
const s = signatures[0];
1316213162
if (!s.typeParameters && s.parameters.length === 1 && signatureHasRestParameter(s)) {
1316313163
const paramType = getTypeOfParameter(s.parameters[0]);
13164-
return isTypeAny(paramType) || getElementTypeOfArrayType(paramType) === anyType;
13164+
const elementType = getElementTypeOfArrayType(paramType)
13165+
return isTypeAny(paramType)
13166+
|| elementType === anyType
13167+
|| elementType === unknownType
1316513168
}
1316613169
}
1316713170
return false;
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
mixinWithUnknownRestParam.ts(14,21): error TS2345: Argument of type 'typeof Base' is not assignable to parameter of type 'ClassConstructor'.
2+
Types of construct signatures are incompatible.
3+
Type 'new (x: number) => Base' is not assignable to type 'new (...args: unknown[]) => {}'.
4+
Types of parameters 'x' and 'args' are incompatible.
5+
Type 'unknown' is not assignable to type 'number'.
6+
7+
8+
==== mixinWithUnknownRestParam.ts (1 errors) ====
9+
// Repro for https://github.com/microsoft/TypeScript/issues/29707
10+
// unknown[] should be a valid mixin constructor constraint, same as any[]
11+
12+
type ClassConstructor = new (...args: unknown[]) => {}
13+
14+
function mixin<C extends ClassConstructor>(Class: C) {
15+
return class extends Class {}
16+
}
17+
18+
class Base {
19+
constructor(public x: number) {}
20+
}
21+
22+
const Mixed = mixin(Base)
23+
~~~~
24+
!!! error TS2345: Argument of type 'typeof Base' is not assignable to parameter of type 'ClassConstructor'.
25+
!!! error TS2345: Types of construct signatures are incompatible.
26+
!!! error TS2345: Type 'new (x: number) => Base' is not assignable to type 'new (...args: unknown[]) => {}'.
27+
!!! error TS2345: Types of parameters 'x' and 'args' are incompatible.
28+
!!! error TS2345: Type 'unknown' is not assignable to type 'number'.
29+
const instance = new Mixed(42)
30+
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
//// [tests/cases/conformance/classes/mixinWithUnknownRestParam.ts] ////
2+
3+
//// [mixinWithUnknownRestParam.ts]
4+
// Repro for https://github.com/microsoft/TypeScript/issues/29707
5+
// unknown[] should be a valid mixin constructor constraint, same as any[]
6+
7+
type ClassConstructor = new (...args: unknown[]) => {}
8+
9+
function mixin<C extends ClassConstructor>(Class: C) {
10+
return class extends Class {}
11+
}
12+
13+
class Base {
14+
constructor(public x: number) {}
15+
}
16+
17+
const Mixed = mixin(Base)
18+
const instance = new Mixed(42)
19+
20+
21+
//// [mixinWithUnknownRestParam.js]
22+
"use strict";
23+
// Repro for https://github.com/microsoft/TypeScript/issues/29707
24+
// unknown[] should be a valid mixin constructor constraint, same as any[]
25+
function mixin(Class) {
26+
return class extends Class {
27+
};
28+
}
29+
class Base {
30+
x;
31+
constructor(x) {
32+
this.x = x;
33+
}
34+
}
35+
const Mixed = mixin(Base);
36+
const instance = new Mixed(42);
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
//// [tests/cases/conformance/classes/mixinWithUnknownRestParam.ts] ////
2+
3+
=== mixinWithUnknownRestParam.ts ===
4+
// Repro for https://github.com/microsoft/TypeScript/issues/29707
5+
// unknown[] should be a valid mixin constructor constraint, same as any[]
6+
7+
type ClassConstructor = new (...args: unknown[]) => {}
8+
>ClassConstructor : Symbol(ClassConstructor, Decl(mixinWithUnknownRestParam.ts, 0, 0))
9+
>args : Symbol(args, Decl(mixinWithUnknownRestParam.ts, 3, 29))
10+
11+
function mixin<C extends ClassConstructor>(Class: C) {
12+
>mixin : Symbol(mixin, Decl(mixinWithUnknownRestParam.ts, 3, 54))
13+
>C : Symbol(C, Decl(mixinWithUnknownRestParam.ts, 5, 15))
14+
>ClassConstructor : Symbol(ClassConstructor, Decl(mixinWithUnknownRestParam.ts, 0, 0))
15+
>Class : Symbol(Class, Decl(mixinWithUnknownRestParam.ts, 5, 43))
16+
>C : Symbol(C, Decl(mixinWithUnknownRestParam.ts, 5, 15))
17+
18+
return class extends Class {}
19+
>Class : Symbol(Class, Decl(mixinWithUnknownRestParam.ts, 5, 43))
20+
}
21+
22+
class Base {
23+
>Base : Symbol(Base, Decl(mixinWithUnknownRestParam.ts, 7, 1))
24+
25+
constructor(public x: number) {}
26+
>x : Symbol(Base.x, Decl(mixinWithUnknownRestParam.ts, 10, 16))
27+
}
28+
29+
const Mixed = mixin(Base)
30+
>Mixed : Symbol(Mixed, Decl(mixinWithUnknownRestParam.ts, 13, 5))
31+
>mixin : Symbol(mixin, Decl(mixinWithUnknownRestParam.ts, 3, 54))
32+
>Base : Symbol(Base, Decl(mixinWithUnknownRestParam.ts, 7, 1))
33+
34+
const instance = new Mixed(42)
35+
>instance : Symbol(instance, Decl(mixinWithUnknownRestParam.ts, 14, 5))
36+
>Mixed : Symbol(Mixed, Decl(mixinWithUnknownRestParam.ts, 13, 5))
37+
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
//// [tests/cases/conformance/classes/mixinWithUnknownRestParam.ts] ////
2+
3+
=== mixinWithUnknownRestParam.ts ===
4+
// Repro for https://github.com/microsoft/TypeScript/issues/29707
5+
// unknown[] should be a valid mixin constructor constraint, same as any[]
6+
7+
type ClassConstructor = new (...args: unknown[]) => {}
8+
>ClassConstructor : ClassConstructor
9+
> : ^^^^^^^^^^^^^^^^
10+
>args : unknown[]
11+
> : ^^^^^^^^^
12+
13+
function mixin<C extends ClassConstructor>(Class: C) {
14+
>mixin : <C extends ClassConstructor>(Class: C) => { new (...args: unknown[]): (Anonymous class); prototype: mixin<any>.(Anonymous class); } & C
15+
> : ^ ^^^^^^^^^ ^^ ^^ ^^^^^^^^^^^^^^^ ^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
16+
>Class : C
17+
> : ^
18+
19+
return class extends Class {}
20+
>class extends Class {} : { new (...args: unknown[]): (Anonymous class); prototype: mixin<any>.(Anonymous class); } & C
21+
> : ^^^^^^^^^^ ^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
22+
>Class : {}
23+
> : ^^
24+
}
25+
26+
class Base {
27+
>Base : Base
28+
> : ^^^^
29+
30+
constructor(public x: number) {}
31+
>x : number
32+
> : ^^^^^^
33+
}
34+
35+
const Mixed = mixin(Base)
36+
>Mixed : { new (...args: unknown[]): mixin<ClassConstructor>.(Anonymous class); prototype: mixin<any>.(Anonymous class); } & ClassConstructor
37+
> : ^^^^^^^^^^ ^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
38+
>mixin(Base) : { new (...args: unknown[]): mixin<ClassConstructor>.(Anonymous class); prototype: mixin<any>.(Anonymous class); } & ClassConstructor
39+
> : ^^^^^^^^^^ ^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
40+
>mixin : <C extends ClassConstructor>(Class: C) => { new (...args: unknown[]): (Anonymous class); prototype: mixin<any>.(Anonymous class); } & C
41+
> : ^ ^^^^^^^^^ ^^ ^^ ^^^^^^^^^^^^^^^ ^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
42+
>Base : typeof Base
43+
> : ^^^^^^^^^^^
44+
45+
const instance = new Mixed(42)
46+
>instance : mixin<ClassConstructor>.(Anonymous class)
47+
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
48+
>new Mixed(42) : mixin<ClassConstructor>.(Anonymous class)
49+
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
50+
>Mixed : { new (...args: unknown[]): mixin<ClassConstructor>.(Anonymous class); prototype: mixin<any>.(Anonymous class); } & ClassConstructor
51+
> : ^^^^^^^^^^ ^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
52+
>42 : 42
53+
> : ^^
54+
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// @strict: true
2+
3+
// Repro for https://github.com/microsoft/TypeScript/issues/29707
4+
// unknown[] should be a valid mixin constructor constraint, same as any[]
5+
6+
type ClassConstructor = new (...args: unknown[]) => {}
7+
8+
function mixin<C extends ClassConstructor>(Class: C) {
9+
return class extends Class {}
10+
}
11+
12+
class Base {
13+
constructor(public x: number) {}
14+
}
15+
16+
const Mixed = mixin(Base)
17+
const instance = new Mixed(42)

0 commit comments

Comments
 (0)