Microsoft/TypeScript

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

Open

#60,881 opened on 2024年12月30日

GitHub で見る
 (0 comments) (0 reactions) (0 assignees)TypeScript (6,726 forks)batch import
Domain: Error MessagesHelp WantedPossible Improvement

Repository metrics

Stars
 (48,455 stars)
PR merge metrics
 (平均マージ 6d 17h) (30d で 9 merged PRs)

説明

🔎 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 https://github.com/typescript-eslint/typescript-eslint/pull/10461#issuecomment-2524252783)

コントリビューターガイド