Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13161,7 +13161,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
const s = signatures[0];
if (!s.typeParameters && s.parameters.length === 1 && signatureHasRestParameter(s)) {
const paramType = getTypeOfParameter(s.parameters[0]);
return isTypeAny(paramType) || getElementTypeOfArrayType(paramType) === anyType;
const elementType = getElementTypeOfArrayType(paramType)
return isTypeAny(paramType)
|| elementType === anyType
|| elementType === unknownType
}
Comment on lines +13164 to 13168
Copy link

Copilot AI Apr 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

isMixinConstructorType now unconditionally calls getElementTypeOfArrayType(paramType), whereas the previous expression only computed the element type when paramType wasn’t any. Since this check can run in class-checking hot paths, consider preserving the short-circuit (e.g. early-return when isTypeAny(paramType) is true). Also, this hunk introduces trailing whitespace and omits semicolons in a file that otherwise consistently uses them; please align formatting, and update the nearby comment that still says the rest parameter must be any[] now that unknown[] is accepted too.

Copilot uses AI. Check for mistakes.
}
return false;
Expand Down
30 changes: 30 additions & 0 deletions tests/baselines/reference/mixinWithUnknownRestParam.errors.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
mixinWithUnknownRestParam.ts(14,21): error TS2345: Argument of type 'typeof Base' is not assignable to parameter of type 'ClassConstructor'.
Types of construct signatures are incompatible.
Type 'new (x: number) => Base' is not assignable to type 'new (...args: unknown[]) => {}'.
Types of parameters 'x' and 'args' are incompatible.
Type 'unknown' is not assignable to type 'number'.
Comment on lines +1 to +5
Copy link

Copilot AI Apr 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This errors baseline asserts TS2345 about typeof Base not being assignable to ClassConstructor, which is unrelated to the PR’s stated goal (accepting unknown[] for mixin constructors) and will remain even after the checker change. If the intent is a positive conformance test for the mixin rule change, the test should be adjusted to compile without errors and the .errors.txt baseline removed/regenerated accordingly.

Copilot uses AI. Check for mistakes.


==== mixinWithUnknownRestParam.ts (1 errors) ====
// Repro for https://github.com/microsoft/TypeScript/issues/29707
// unknown[] should be a valid mixin constructor constraint, same as any[]

type ClassConstructor = new (...args: unknown[]) => {}

function mixin<C extends ClassConstructor>(Class: C) {
return class extends Class {}
}

class Base {
constructor(public x: number) {}
}

const Mixed = mixin(Base)
~~~~
!!! error TS2345: Argument of type 'typeof Base' is not assignable to parameter of type 'ClassConstructor'.
!!! error TS2345: Types of construct signatures are incompatible.
!!! error TS2345: Type 'new (x: number) => Base' is not assignable to type 'new (...args: unknown[]) => {}'.
!!! error TS2345: Types of parameters 'x' and 'args' are incompatible.
!!! error TS2345: Type 'unknown' is not assignable to type 'number'.
const instance = new Mixed(42)

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

//// [mixinWithUnknownRestParam.ts]
// Repro for https://github.com/microsoft/TypeScript/issues/29707
// unknown[] should be a valid mixin constructor constraint, same as any[]

type ClassConstructor = new (...args: unknown[]) => {}

function mixin<C extends ClassConstructor>(Class: C) {
return class extends Class {}
}

class Base {
constructor(public x: number) {}
}

const Mixed = mixin(Base)
const instance = new Mixed(42)


//// [mixinWithUnknownRestParam.js]
"use strict";
// Repro for https://github.com/microsoft/TypeScript/issues/29707
// unknown[] should be a valid mixin constructor constraint, same as any[]
function mixin(Class) {
return class extends Class {
};
}
class Base {
x;
constructor(x) {
this.x = x;
}
}
const Mixed = mixin(Base);
const instance = new Mixed(42);
37 changes: 37 additions & 0 deletions tests/baselines/reference/mixinWithUnknownRestParam.symbols
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
//// [tests/cases/conformance/classes/mixinWithUnknownRestParam.ts] ////

=== mixinWithUnknownRestParam.ts ===
// Repro for https://github.com/microsoft/TypeScript/issues/29707
// unknown[] should be a valid mixin constructor constraint, same as any[]

type ClassConstructor = new (...args: unknown[]) => {}
>ClassConstructor : Symbol(ClassConstructor, Decl(mixinWithUnknownRestParam.ts, 0, 0))
>args : Symbol(args, Decl(mixinWithUnknownRestParam.ts, 3, 29))

function mixin<C extends ClassConstructor>(Class: C) {
>mixin : Symbol(mixin, Decl(mixinWithUnknownRestParam.ts, 3, 54))
>C : Symbol(C, Decl(mixinWithUnknownRestParam.ts, 5, 15))
>ClassConstructor : Symbol(ClassConstructor, Decl(mixinWithUnknownRestParam.ts, 0, 0))
>Class : Symbol(Class, Decl(mixinWithUnknownRestParam.ts, 5, 43))
>C : Symbol(C, Decl(mixinWithUnknownRestParam.ts, 5, 15))

return class extends Class {}
>Class : Symbol(Class, Decl(mixinWithUnknownRestParam.ts, 5, 43))
}

class Base {
>Base : Symbol(Base, Decl(mixinWithUnknownRestParam.ts, 7, 1))

constructor(public x: number) {}
>x : Symbol(Base.x, Decl(mixinWithUnknownRestParam.ts, 10, 16))
}

const Mixed = mixin(Base)
>Mixed : Symbol(Mixed, Decl(mixinWithUnknownRestParam.ts, 13, 5))
>mixin : Symbol(mixin, Decl(mixinWithUnknownRestParam.ts, 3, 54))
>Base : Symbol(Base, Decl(mixinWithUnknownRestParam.ts, 7, 1))

const instance = new Mixed(42)
>instance : Symbol(instance, Decl(mixinWithUnknownRestParam.ts, 14, 5))
>Mixed : Symbol(Mixed, Decl(mixinWithUnknownRestParam.ts, 13, 5))

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

=== mixinWithUnknownRestParam.ts ===
// Repro for https://github.com/microsoft/TypeScript/issues/29707
// unknown[] should be a valid mixin constructor constraint, same as any[]

type ClassConstructor = new (...args: unknown[]) => {}
>ClassConstructor : ClassConstructor
> : ^^^^^^^^^^^^^^^^
>args : unknown[]
> : ^^^^^^^^^

function mixin<C extends ClassConstructor>(Class: C) {
>mixin : <C extends ClassConstructor>(Class: C) => { new (...args: unknown[]): (Anonymous class); prototype: mixin<any>.(Anonymous class); } & C
> : ^ ^^^^^^^^^ ^^ ^^ ^^^^^^^^^^^^^^^ ^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>Class : C
> : ^

return class extends Class {}
>class extends Class {} : { new (...args: unknown[]): (Anonymous class); prototype: mixin<any>.(Anonymous class); } & C
> : ^^^^^^^^^^ ^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>Class : {}
> : ^^
}

class Base {
>Base : Base
> : ^^^^

constructor(public x: number) {}
>x : number
> : ^^^^^^
}

const Mixed = mixin(Base)
>Mixed : { new (...args: unknown[]): mixin<ClassConstructor>.(Anonymous class); prototype: mixin<any>.(Anonymous class); } & ClassConstructor
> : ^^^^^^^^^^ ^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>mixin(Base) : { new (...args: unknown[]): mixin<ClassConstructor>.(Anonymous class); prototype: mixin<any>.(Anonymous class); } & ClassConstructor
> : ^^^^^^^^^^ ^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>mixin : <C extends ClassConstructor>(Class: C) => { new (...args: unknown[]): (Anonymous class); prototype: mixin<any>.(Anonymous class); } & C
> : ^ ^^^^^^^^^ ^^ ^^ ^^^^^^^^^^^^^^^ ^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>Base : typeof Base
> : ^^^^^^^^^^^

const instance = new Mixed(42)
>instance : mixin<ClassConstructor>.(Anonymous class)
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>new Mixed(42) : mixin<ClassConstructor>.(Anonymous class)
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>Mixed : { new (...args: unknown[]): mixin<ClassConstructor>.(Anonymous class); prototype: mixin<any>.(Anonymous class); } & ClassConstructor
> : ^^^^^^^^^^ ^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>42 : 42
> : ^^

17 changes: 17 additions & 0 deletions tests/cases/conformance/classes/mixinWithUnknownRestParam.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// @strict: true

// Repro for https://github.com/microsoft/TypeScript/issues/29707
// unknown[] should be a valid mixin constructor constraint, same as any[]

type ClassConstructor = new (...args: unknown[]) => {}

function mixin<C extends ClassConstructor>(Class: C) {
return class extends Class {}
}

class Base {
constructor(public x: number) {}
}

const Mixed = mixin(Base)
Comment on lines +12 to +16
Copy link

Copilot AI Apr 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new test currently fails with TS2345 at the call site because Base (constructor (x: number)) is not assignable to new (...args: unknown[]) => {} under --strict. This introduces an unrelated error and prevents the test from cleanly validating the intended mixin/constructor behavior. Consider removing the mixin(Base) usage or changing Base to satisfy the unknown[] constructor constraint so the test exercises only the targeted regression.

Copilot uses AI. Check for mistakes.
const instance = new Mixed(42)
Loading