microsoft / microsoft/TypeScript
misleading error message on invalid assignment when one type parameter extends another
Nobody has claimed this yet.
- Dominant language
- Go
- Stars
- 111k
- Forks
- 14.3k
- Avg merge
- 2d 4h
- Merged PRs (30d)
- 132
Description
🔎 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
💻 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)
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with the linked TypeScript Playground reproductions and compare the diagnostic for the generic assignment with the ordinary constrained-type example. Locate the compiler diagnostic path responsible for the wording, then add regression coverage for the reported case and verify that the resulting message explains the subtype constraint accurately.
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
- 45/100