Skip to content

Wrong type assertion in classes using "this" keyword #49851

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

Closed
nicolasmelo1 opened this issue Jul 10, 2022 · 2 comments
Closed

Wrong type assertion in classes using "this" keyword #49851

nicolasmelo1 opened this issue Jul 10, 2022 · 2 comments

Comments

@nicolasmelo1
Copy link

nicolasmelo1 commented Jul 10, 2022

Bug Report

πŸ”Ž Search Terms

this, assertion error, generics, type inference, automatic intersection

πŸ•— Version & Regression Information

Looks like it's above version 3.3.3333

⏯ Playground Link

Playground link with relevant code

πŸ’» Code

// -------- BASE CLASSES ---------------
class Model {
  fields!: ModelFields;
  options!: ModelOptions<this>;
}

// ------- BUG ------------------------
class User extends Model {
  fields = {
    a: FieldTypes.BOOL
  }
//                        V - ⛔️ HERE IS THE BUG!!!! Why? and how to solve it?
  options: ModelOptions<this> = {
    indexes: [{
      unique: true,
      fields: ['a'] // <- βœ… This works as expected though
    }]
  }
}

// ------------ TYPES ----------------
enum FieldTypes {
  CHAR = 'CHAR',
  BOOL = 'BOOL',
  INT = 'INT'
}

type ModelIndex<M extends Model> = {
  unique: true;
  fields: (keyof M["fields"])[];
}

type OrderingOfModelOptions<M extends Model> = keyof M["fields"]|
  keyof { [F in keyof M["fields"] as F extends string ? `-${F}` : never] : 1}

type ModelOptions<M extends Model> = {
  indexes?: ModelIndex<M>[];
  ordering?: OrderingOfModelOptions<M>[];
}

type ModelFields = {
  [field: string]: FieldTypes
}

πŸ™ Actual behavior

Although i'm passing the correct arguments, it just don't work. It just don't work because the type ModelIndexes is an object, which is really strange to me.

  • I've tried changing the name of the fields to something else like attributes but no success, so it does not seem that the problem is the name.
  • I saw that on ModelIndexes it looks like M and Model are having an automatic intersection like M & Model, but it needs some further investigation.
  • I've tried doing conditional like M extends Model ? (keyof M["fields"])[] : never; but no success, the condition actually works but the problem then will be something like Type '"a"[]' is not assignable to type 'this extends Model ? (keyof this["fields"])[] : never

πŸ™‚ Expected behavior

in this example indexes: { union: true, fields: ['a']} should work because 'a' is defined in the User model fields object and indexes: { union: true, fields: ['b']} should not work because 'b' it's not defined inside of fields in User model

The expected behavior is to just work as 3.3.3 worked, so it accepts a union of all of the keys of the object not as all of the above versions works.

@MartinJohns
Copy link
Contributor

MartinJohns commented Jul 10, 2022

Your property fields has the type { a: FieldTypes }, but your generic type ModelOptions<> requires the type argument to extend Model. But the type of this is { fields: { a: FieldTypes } }, and it does not extend Model (which is { fields: ModelFields; options: ModelOptions<this> }).

When you type your property fields correctly it works:

class User extends Model {
  fields: ModelFields = {
    a: FieldTypes.BOOL
  }
  // ...
}

The type of re-defined properties is not inherited. This would require #10570.

@nicolasmelo1
Copy link
Author

Whoa, nobody was being able to solve this, yeah, it works as expected now, and now i understood why this error happens.

Thanks a lot for the help and explanation, closing the issue now.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants