Home > Enterprise >  Typescript type A is not assignable to type A (same type)
Typescript type A is not assignable to type A (same type)

Time:04-14

I'm having an issue where Typescript tells me that type A is not assignable to type A, but they're exactly the same:

Here is a link to the playground:

declare interface ButtonInteraction {
  user: any;
  customId: string;
  reply: (message: string) => void
}

enum TranslatorLangs {
  FR = 'fr',
  EN = 'en',
}

export class UserService {
  public async setUserLocale(user: any, locale: TranslatorLangs): Promise<any> {
    user.locale = locale;
  }
}

export interface ButtonHandlerInterface {
  commandName: string;
  handle<T = unknown>(interaction: ButtonInteraction, value: T): void | Promise<void>
}

export default class MbtiCommandHandler implements ButtonHandlerInterface {
  public commandName = 'setLocale';

  private userService: UserService = new UserService();

  async handle<TranslatorLangs>(interaction: ButtonInteraction, value: TranslatorLangs): Promise<void> {
    this.userService.setUserLocale(interaction.user, value);
    //                                               ^^^^^
    //                         Argument of type 'TranslatorLangs' is not assignable to parameter of type 'TranslatorLangs'
    interaction.reply(`Ok, so it will be ${interaction.customId}`);

    return interaction.reply('ok');
  }
}

CodePudding user response:

They're not actually the same thing, the name "TranslatorLangs" is being used to mean two different things. First, it's an enum. Second, it's a name for the generic parameter than handle accepts. To rename it so i can refer to them separately, let's change the handle function to:

async handle<T>(interaction: ButtonInteraction, value: T): Promise<void>

This line is saying that handle is a generic function. "T" is a placeholder for whatever type they decide to call it with. They might decide that T is TranslatorLangs, but they could also pass in anything else, such as a boolean. So when you try to pass that boolean into setUserLocale, you get an error.

I think what you're trying to do is make ButtonHandlerInterface itself be generic, as in:

export interface ButtonHandlerInterface<T = unknown> {
  commandName: string;
  handle(interaction: ButtonInteraction, value: T): void | Promise<void>
}

You'll then use it like this:

export default class MbtiCommandHandler implements ButtonHandlerInterface<TranslatorLangs> {
   // ...
  async handle(interaction: ButtonInteraction, value: TranslatorLangs): Promise<void> {
  // ...

Playground link

  • Related