-
Notifications
You must be signed in to change notification settings - Fork 12.6k
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
Class inheritance should not bypass generic parameter contravariance #53798
Comments
I believe this is essentially the same problem described at #48240 (comment). In your example the generic parameter |
Okay I understand the problem. But in any case, when a parameter is marked with the |
While Iβm inclined to agree this is surprising, itβs also a fundamental design limitation because the type system is primarily structural. If contravariance isnβt witnessed in the structure of the type then youβre going to lose that information when using a type identity that doesnβt include the From what I understand variance annotations were added more for the benefit of the implementer than the consumer, for exactly this reason. So |
Put another way: If you write |
This is the intentional behavior. Variance annotations only apply when you're comparing two instantiations of the same type; this is the only place it even makes sense to think about doing it in the first place. POLA is ungeneralizable, but to me this isn't surprising at all. TypeScript is a structural type system and The only plausible diff I could imagine here would be erroring on the |
Well, then indeed I have to admit I'm facing the limits of TypeScript's design, which makes things like that being accepted although they don't make any sense. Anyway, thank you all for your answers. |
It's maybe a bit surprising if one is expecting the variance annotation to be part of structure (i.e. being a property of the type parameter |
By the way I tried the code snippet given in the Why are function parameters bivariant? FAQ section and it actually gives a compile error (which is very welcome π) playground example Is this section outdated? |
Yeah, I've brought it up before that that section is outdated. π It used to be that all function types were bivariant but https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-6.html#strict-function-types
If methods were strictly checked, But of course this implies that if you really do want the stricter checking for your methods, you have the option of using an interface with function-typed properties instead of methods. |
Alright thank you! It is clearer for me now. |
This issue has been marked 'Working as Intended' and has seen no recent activity. It has been automatically closed for house-keeping purposes. |
Bug Report
π Search Terms
contravariance bypass inheritance variance annotation
π Version & Regression Information
β― Playground Link
Playground link with relevant code
π» Code
In this example we use contravariance to make
Comparator<Animal>
assignable toComparator<Dog>
: something than can compare animals can compare dogs.π Actual behavior
The following line is accepted by the compiler:
I think the problem is that as
DogComparator
is a subclass ofComparator
, the compiler only checks for(a: Dog, b: Dog) => boolean
to be assignable to(a: Animal, b: Animal) => void
, regardless of contravariance annotation put on the generic type.π Expected behavior
The nok line above should give a compilation error as contravariance on
Comparator
's generic parameter should preventDogComparator
(which extendsComparator<Dog>
) from being treated as aComparator<Animal>
.Even if
(a: Dog, b: Dog) => boolean
is assignable to(a: Animal, b: Animal) => void
, there should be a second contraint to check ifAnimal
is a subtype ofDog
(which will give the error) because of contravariance on the generic parameter.For information this is the case in Kotlin: see this playground sample
Thanks π
The text was updated successfully, but these errors were encountered: