-
Notifications
You must be signed in to change notification settings - Fork 13.3k
fix(checker): allow unknown[] as valid mixin constructor rest param type #63362
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| 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
|
||
|
|
||
|
|
||
| ==== 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) | ||
|
|
||
| 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); |
| 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)) | ||
|
|
| 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 | ||
| > : ^^ | ||
|
|
| 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
|
||
| const instance = new Mixed(42) | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
isMixinConstructorTypenow unconditionally callsgetElementTypeOfArrayType(paramType), whereas the previous expression only computed the element type whenparamTypewasn’tany. Since this check can run in class-checking hot paths, consider preserving the short-circuit (e.g. early-return whenisTypeAny(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 beany[]now thatunknown[]is accepted too.