- Notifications
You must be signed in to change notification settings - Fork 13.2k
Description
Variance and Variance Annotations on Type Parameters
(continued from #48209)
typeFoo<T>={x: T;f: FooFn<T>;};typeFooFn<T>=(foo: Bar<T[]>)=>void;typeBar<T>={value: Foo<T[]>;};// Try this in TypeScript 4.6.// Whether or not you see an error on 'fn2 = fn1'// depends on whether or not Section (B) comes before Section (A)// Section (A)declareletfoo1: Foo<string>;declareletfoo2: Foo<unknown>;foo1=foo2;foo2=foo1;// Section (B)declareletfn1: FooFn<string>;declareletfn2: FooFn<unknown>;fn1=fn2;fn2=fn1;Could handle these better, but would break code.
Idea: variance annotations
Compare
Tby covariant rules:typeFoo<outT>={x: T;f: FooFn<T>;};
Compare
Tby contravariant rules:typeFoo<inT>={x: T;f: FooFn<T>;};
Compare
Tby invariant rules:typeFoo<inoutT>={x: T;f: FooFn<T>;};
Can help with documentation, correctness, perf.
- Perf results? 10-20% improvements because we have to measure variance.
- This short-circuits any circularity.
Existing code that doesn't use these gets nothing out of it.
- Should we emit these annotations in
.d.tsfiles if we can accurately measure?- We can come up with states like bivariant, unmeasurable, and independent. Won't try to represent those. But for some subset (i.e. covariant, contravariant, invariant), we could do that.
- But introducing these in declaration files would be a breaking change for downstream
.d.tsconsumers! - Start out by not doing this unless a user explicitly specified it.
- Should we emit these annotations in
Would be nice if we could surface this information in quick info though.
Interface merging combines the variance annotations.
- Does that mean that interface emerging can invalidate the annotation of another interface?
- Yes, but this was always the case. The compiler will issue an error and you'll manually have to fix that up.
- Does that mean that interface emerging can invalidate the annotation of another interface?
Variance annotations on generic signatures we don't allow - doesn't make sense.
- Doesn't it? We do a lot of work on this sort of thing.
Error messages?
- Could special-case the last part.
- Avoid saying "covariant" or "contravariant" - "input position" and "output position".
- We report based on the marker types, using
SuperandSubas the displayed names.- Those could be real names.
Who would benefit the most from the perf aspect here?
- xstate, lodash, immutable, Ember?
- Could use
typesVersionsto just give an instant perf boost to 4.7 users if this ships by then. - We don't have a way to measure "how much time is being spent in variance"
Maybe urge caution.
- Lots of stuff that stops working if you start marking everything as
in out(invariant).
- Lots of stuff that stops working if you start marking everything as
Do we feel okay about the fact that two instantiations of the same type might be incompatible but structurally identical types would be compatible?
- Yes-ish.
- Usually the names of types are not material.
- Really means we have to message this well.
- Invariant is the only place where you can throw off how the type-checker is usually used.
- Well if you say co/contravariant when we would've otherwise measured bivariant.
in outfuture-proofs the API - kinda nice.
- Yes-ish.
So declaration emit?
- No, not automatically. Breaking change for older versions.
This will force us to create a 4.7-based rift on DefinitelyTyped.
typesVersions?- If you use JSDoc, it's ignored by older versions.
- Out of band file?
Should we have some sort of support for JSDoc here?
How does this play with "Types as Comments"?
- Doesn't affect it, the proposal ignores content between
<and>
- Doesn't affect it, the proposal ignores content between
JSDoc for variance annotations?
- It might be the case that we need to lean on JSDoc for
public,private,protected. - So
inandout.
- It might be the case that we need to lean on JSDoc for
Our node factory APIs would need to take a breaking change.
- We've done this, but people understandably are unhappy about it.
- Optional parameters? Arity check won't work.
NodeFlags?- Overload that checks the first argument, and maybe deprecates the old overload?
Back to syntax!
- So actual keywords?
- Minimally yes, but also indecisive about back-compat and allowing
/** @in @out */
- Minimally yes, but also indecisive about back-compat and allowing
- So actual keywords?