microsoft / microsoft/TypeScript

Mixin / Inheritance problem with Typescript - string not assignable to string|number|symbol

Open
#52,907 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Bug Domain: classes Help Wanted
Dominant language
Go
Stars
111k
Forks
14.3k
Avg merge
1d 19h
Merged PRs (30d)
117

Description

Bug Report

I have a typescript class. I'd like to subclass it and add a mixin. However, it keeps telling me that string not assignable to string|number|symbol. I don't understand why because the method signatures are the same.

🔎 Search Terms

typescript mixin prototype

🕗 Version & Regression Information

4.9.5

I just started using Typescript, so 4.9.5 is the version I was using since I started seeing it.

⏯ Playground Link

this shows the problem with UserRecord

this shows the way to work around the problem

💻 Code

This is as short as I can make the example and still show what's happening:

type TModel = {
    'User' : {
        username : string,
        password : string  | undefined,
    },
    'APIKey' : {
        privateKey: string,
    }
};
type TProps<T extends keyof TModel> = Partial<TModel[T]>;

type Constructor<T = {}> = new (...args: any[]) => T;

 class VingRecord<T extends keyof TModel> {
    constructor( private props: TProps<T>) { }

    public set<K extends keyof TProps<T>>(_key: K) {}
}

function RoleMixin<T extends Constructor>(Base: T) {
    return class RoleMixin extends Base {  };
}

class UserRecord extends RoleMixin(VingRecord<'User'>) {
    public set<K extends keyof TProps<'User'>>(_key: K) {}
}

and if you replace the RoleMixin with this it hides the problem with the funky prototype:

function RoleMixin<T extends IConstructable>(Base: T) {
    class RoleMixin extends Base {};
    return RoleMixin as {
        new (...args: any): RoleMixin;
        prototype: any;
    } & T;
}
🙁 Actual behavior

The code works, but typescript has a problem with the mixin thinking the type on VingRecord is any rather than 'User'. So it reports a type mismatch on the UserRecord.

More detail here with the guys who spotted the behavior

🙂 Expected behavior

I should be able to do the inheritance as shown in the code sample above without having to do the funky return from the mixin.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the linked TypeScript Playground reproduction and compare it with the linked workaround, focusing on generic mixin and inheritance handling. The issue is done when the original example type-checks without the workaround while preserving the 'User' type through UserRecord.

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
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.