Skip to content
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

misleading error message on invalid assignment when one type parameter extends another #60881

Open
kirkwaiblinger opened this issue Dec 30, 2024 · 0 comments
Labels
Help Wanted You can do this Possible Improvement The current behavior isn't wrong, but it's possible to see that it might be better in some cases
Milestone

Comments

@kirkwaiblinger
Copy link

kirkwaiblinger commented Dec 30, 2024

🔎 Search Terms

generic, type parameter, extends, arbitrary type which could be unrelated, assignment

🕗 Version & Regression Information

  • This changed between versions TS 3.8.3 and TS 3.9.7 (well, the pre-3.9 message isn't perfect, tbh but it only becomes fully wrong after that)

⏯ Playground Link

https://www.typescriptlang.org/play/?target=99&ts=5.8.0-dev.20241229&noUncheckedIndexedAccess=false#code/GYVwdgxgLglg9mABABwIYCdUFsCmUfoCiAHvmACYDOA8lABYEAKG2eBAPAMojIEAqAT14AaRNwBGg3ohykcFSmJ78hOAHwAKSsvRScALiW9dq0dsmrDEvQEpEAbwBQiRAHpXiPp0QBmAHQ+hnqIAOTcxnohiDCKYHBQiKiUlDAA5mCo4gA2OIhQcHmqodaqIX7Obq4V7p7e-gCsQUVhOpHRsfGJyWkZ2bn5hdItFrxliNUeLlNTLRGl7V0p6Zk5eQX0uRAIlFCYMGAJcMCDucORouIgCWfzWyBZ5Ijiufs7qAcwqPiPAO4w9IlEOQYMBgAR5AlzFAikdEFswDs9gdQvYAL5lCYTWq+PwATiaQ3CKlGCziCSSS16qwG0MJIBGOAxLhq02mNxJdweTxeCKg71gXxwv3+dESSAw4n+mHQAhOiB+dBgEFFnMez0Q4HQOCygseA1mxMZ5WZVRN2IALH4ABwE05EkwkmKIMmLHorfrrZolUbGyqstnexlwuD3NU8t4fXXykVixLoSW7DCy2m5BVKlUhrnqzXaqP6+2RX0s-3RMDIK5+KCUYgaACMonNtZsQUVihTKBYuHw6EQWDSdASYBwQtjAANZGQqIgAGqj4O8pFQX3mYIAXkQ2jmvAA3I5UUA

💻 Code

function parameterExtendsOtherParameter<SuperType, SubType extends SuperType>(superType: SuperType, subType: SubType) {
  // TS 3.3: Type 'SuperType' is not assignable to type 'SubType'.
  //
  // TS 3.5: Type 'SuperType' is not assignable to type 'SubType'. 
  //         'SuperType' is assignable to the constraint of type 'SubType', but 'SubType' could be instantiated with a different subtype of constraint '{}'.
  //
  // TS 3.9: Type 'SuperType' is not assignable to type 'SubType'.
  //         'SubType' could be instantiated with an arbitrary type which could be unrelated to 'SuperType'.
  //
  // TS 4.8: Type 'SuperType' is not assignable to type 'SubType'.
  //         'SubType' could be instantiated with an arbitrary type which could be unrelated to 'SuperType'.
  //         input.tsx(1, 41): This type parameter might need an `extends V` constraint.
  subType = superType;
}

🙁 Actual behavior

Type 'SuperType' is not assignable to type 'SubType'.
   'SubType' could be instantiated with an arbitrary type which could be unrelated to 'SuperType'.
   input.tsx(1, 41): This type parameter might need an `extends SubType` constraint.

The misleading thing here is that SubType plainly cannot be unrelated to SuperType. It's guaranteed to be a subtype of SuperType, since it extends SuperType.

🙂 Expected behavior

The TS 3.5 error message was nearly there (just swapped {} for SuperType)...

Type 'SuperType' is not assignable to type 'SubType'.
'SuperType' is assignable to the constraint of type 'SubType', but 'SubType' could be instantiated with a different subtype of constraint 'SuperType'.

I might suggest something like this instead though:

type 'SuperType' is not assignable to type 'SubType'. 
'SubType' is constrained to be a subtype of 'SuperType'.
input.tsx: You might have swapped the left and right hand sides of the assignment.

This is nearly a garden-variety instance of assigning a wider type to a narrower type, it just looks tricky because of the presence of generics and extends.

Additional information about the issue

contrast with this example:
(playground)

function parameterExtendsOrdinaryType<StringSubType extends string>(s: string, subType: StringSubType) {
  //  Type 'string' is not assignable to type 'StringSubType'.
  //   'string' is assignable to the constraint of type 'StringSubType', but 'StringSubType' could be instantiated with a different subtype of constraint 'string'
  subType = s;
}

cc @controversial (discovered in typescript-eslint/typescript-eslint#10461 (comment))

@RyanCavanaugh RyanCavanaugh added Help Wanted You can do this Possible Improvement The current behavior isn't wrong, but it's possible to see that it might be better in some cases labels Jan 2, 2025
@RyanCavanaugh RyanCavanaugh added this to the Backlog milestone Jan 2, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Help Wanted You can do this Possible Improvement The current behavior isn't wrong, but it's possible to see that it might be better in some cases
Projects
None yet
Development

No branches or pull requests

2 participants