microsoft / microsoft/TypeScript
[3.5.0-dev.20190516] Incorrect type error for mixin
Nobody has claimed this yet.
- Dominant language
- Go
- Stars
- 111k
- Forks
- 14.3k
- Avg merge
- 2d 4h
- Merged PRs (30d)
- 132
Description
When using the mixin pattern, there are 2 main notations to define the type of the mixin entity.
The mixin pattern:
export type AnyFunction<A = any> = (...input : any[]) => A
export type AnyConstructor<A = object> = new (...input : any[]) => A
export type Mixin<T extends AnyFunction> = InstanceType<ReturnType<T>>
export const Box = <T extends AnyConstructor<object>>(base : T) =>
class Box extends base {
value : any
}
1st notation:
export type Box = Mixin<typeof Box> {}
2nd notation:
export interface Box extends Mixin<typeof Box> {}
The 1st notation can not be used for recursive definitions (#29872). Because of that we primarily use 2nd notation. It works fine in most cases, however I found a case, when it produces invalid type error. The full snippet to reproduce the problem below.
Note:
- The typechecker correctly figures out that there's no
zxcproperty onthis, inside theobservemethod ofQuarkmixin. - In that method, it does not complain about the
this.valueusage - It does complain, when
valueis used on function argument - If you'll switch the
Quarkmixin to the 1st notation, the error will disappear
Expected behavior:
- No type errors for the definition of
testfunction below
export type AnyFunction<A = any> = (...input : any[]) => A
export type AnyConstructor<A = object> = new (...input : any[]) => A
export type Mixin<T extends AnyFunction> = InstanceType<ReturnType<T>>
export const Box = <T extends AnyConstructor<object>>(base : T) =>
class Box extends base {
value : any
}
export interface Box extends Mixin<typeof Box> {}
export const Observable = <T extends AnyConstructor<object>>(base : T) =>
class Observable extends base {
observe () : Quark {
return
}
}
export interface Observable extends Mixin<typeof Observable> {}
export const Quark = <T extends AnyConstructor<Box & Observable>>(base : T) =>
class Quark extends base {
observe () : Quark {
// No error here!
this.value
// error: Error:(28, 14) TS2339: Property 'zxc' does not exist on type 'Quark'.
this.zxc
return
}
}
export interface Quark extends Mixin<typeof Quark> {}
const test = (a : Quark) => a.value // <-- Error:(35, 28) TS2339: Property 'value' does not exist on type 'Quark'.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by compiling the complete TypeScript reproducer in this issue and compare the two Quark mixin notations. Trace how the checker resolves the inherited value property inside Quark and on the test function argument. Done means the second notation produces no type error for a.value while the invalid this.zxc access still reports an error.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- compilers
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 52/100