Closed
Description
TypeScript Version: 3.6.4 & 3.7.2 & 3.8.0-dev.20191112
Search Terms: generic constraints, TS2322, 2322
Code
export class Model<GenericSchema extends { id: string }> {
public fails(): GenericSchema {
return { id: '' }; // <-- This line produce the error, see below
}
public works(): GenericSchema {
return { id: '' } as GenericSchema;
}
}
Expected behavior:
Should compile without errors. To me this should work since the the fails()
method returns an object which satisfies the constraint { id: string }
.
Actual behavior:
3:5 - error TS2322: Type '{ id: string; }' is not assignable to type 'GenericSchema'.
'{ id: string; }' is assignable to the constraint of type 'GenericSchema', but 'GenericSchema' could be instantiated with a different subtype of constraint '{ id: string; }'.
Context:
For additional context, I originally filed an issue with @types/mongodb
which gives the original use case
DefinitelyTyped/DefinitelyTyped#39358
Last, here is a discussion of the exact same matter on Stack Overflow
https://stackoverflow.com/questions/58663733/typescript-class-generic-constraint
Playground Link:
https://codesandbox.io/s/mapped-type-with-generics-l4b0b
Related Issues:
I believe this is related to #34567 and as such probably also #33014.
Metadata
Metadata
Assignees
Type
Projects
Milestone
Relationships
Development
No branches or pull requests
Activity
fatcerberus commentedon Nov 13, 2019
The error here is correct.
Model
could be instantiated, for example, withGenericSchema = { id: string, foo: string }
, which is assignable to{ id: string }
. The inverse, however, is not true.It satisfies the constraint, yes, but it doesn't satisfy all possible types that
GenericSchema
could be. Type parameters are universally quantified--that's the purpose of using a generic.AnyhowStep commentedon Nov 13, 2019
Here's a concrete example of the kind of error TS is trying to protect you from,
Playground
lirbank commentedon Nov 15, 2019
Thanks a lot for the example, that makes a lot of sense!
In my real use case I'm accessing a database so it would be OK for
obj.x
to be out of sync, since this would be a developer error (providing the wrong type for the data model in the DB). That said, to me it now (with your help) seems the TS compile is handling the above example correctly.Now, if I change the example to be a bit closer to a real use case with an external db driver module, it may look something like this. And now the compiler accepts the generic as a return type, without the type assertion - which also makes sense.
Playground
A more contrived example:
Playground
In summary, my initial example was simply not correct and both examples works as expected. I'll close this issue and bring the matter back over to the
@types/mongodb
DefinitelyTyped/DefinitelyTyped#39358 package.Big thanks for your help @fatcerberus and @AnyhowStep!
RyanCavanaugh commentedon Nov 15, 2019
https://twitter.com/SeaRyanC/status/1121995986862084096