GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — Optional variance annotations by ahejlsberg · Pull Request #48240 · microsoft/TypeScript

Conversation

@ahejlsberg

@ahejlsberg Anders Hejlsberg (ahejlsberg) commented Mar 13, 2022 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Member

With this PR we introduce optional declaration site variance annotations for type parameters of classes, interfaces and type aliases. Annotations take the form of an in and/or out keyword immediately preceding the type parameter name in a type parameter declaration.

  • An out annotation indicates that a type parameter is covariant.
  • An in annotation indicates that a type parameter is contravariant.
  • An in out annotation indicates that a type parameter is invariant.

Generally, type parameter variance is simply a function of how a type parameter is used in its generic subject type. Indeed, when generic type instantiations are related structurally, variance annotations serve no purpose. This is why TypeScript strictly doesn't need variance annotations. However, variance annotations are useful to assert desired type relations of their subject generic types. Specifically, given a generic type G<T> and any two type arguments Super and Sub for which Sub is a subtype of Super,

  • if T is covariant (declared as out T), G<Sub> is a subtype of G<Super>,
  • if T is contravariant (declared as in T), G<Super> is a subtype of G<Sub>, and
  • if T is invariant (declared as in out T), neither G<Super> nor G<Sub> is a subtype of the other.

Intuitively, covariance restricts a type parameter to output (read) positions and contravariance restricts a type parameter to input (write) positions--hence the in and out modifiers. For example:

type Provider<out T> = () => T;
type Consumer<in T> = (x: T) => void;
type Mapper<in T, out U> = (x: T) => U;
type Processor<in out T> = (x: T) => T;

Covariance and contravariance annotations are checked by structurally relating representative instantiations of their subject generic types. For example, in the following generic type, the type parameter T is used in both input and output positions and T is thus invariant. Attempting to mark T covariant

type Foo<out T> = {
    x: T;
    f: (x: T) => void;
}

reports the following error on out T:

Type 'Foo<sub-T>' is not assignable to type 'Foo<super-T>' as implied by variance annotation.
  Types of property 'f' are incompatible.
    Type '(x: sub-T) => void' is not assignable to type '(x: super-T) => void'.
      Types of parameters 'x' and 'x' are incompatible.
        Type 'super-T' is not assignable to type 'sub-T'.

Likewise, attempting to mark T contravariant

type Foo<in T> = {
    x: T;
    f: (x: T) => void;
}

reports the following error on in T:

Type 'Foo<super-T>' is not assignable to type 'Foo<sub-T>' as implied by variance annotation.
  Types of property 'x' are incompatible.
    Type 'super-T' is not assignable to type 'sub-T'.

Notice how the error elaborations reveal where and how variance is breached.

Invariance annotations (in out T) are never checked but simply assumed to hold. Thus, it is possible to assert invariance even when the actual usage of a type parameter is co- or contravariant.

When multiple interface declarations are merged, or when a class declaration and one or more interface declarations are merged, variance annotations are aggregated. In the example

interface Bar<T> {
    // ...
}

interface Bar<out T> {
    // ...
}

interface Bar<in T> {
    // ...
}

the aggregate variance of T is in out, and T is thus assumed to be invariant.

When variance annotations are present, the type checker doesn't need to measure variance. Thus, variance annotations can help improve the performance of checking complex and interdependent types. In particular, marking a type parameter invariant means that no measurement or checking is necessary for that type parameter.

In addition, variance annotation can help establish correct variance for multiple circularly dependent generic types. Specifically, when measuring variance, TypeScript limits the structural search space in order to avoid runaway recursion. In the example

type Foo<T> = {
    x: T;
    f: Bar<T>;
}

type Bar<U> = (x: Baz<U[]>) => void;

type Baz<V> = {
    value: Foo<V[]>;
}

declare let foo1: Foo<unknown>;
declare let foo2: Foo<string>;

foo1 = foo2;  // Should be an error but isn't
foo2 = foo1;  // Error

the compiler measures T to be covariant even though it is actually invariant due to variance reversal in Bar and the circular reference in Baz. The compiler could establish that by continuing to structurally relating nested circular references until some fixed point, but this gets exponentially expensive and isn't feasible in complex scenarios. Adding an in out annotation to T establishes the correct variance and produces the expected errors.

We're marking #1394 and #10717 fixed by this PR, although the feature implemented isn't exactly what is suggested in those issues.

Fixes #1394.
Fixes #10717.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

IllusionMH, r-cyr, whzx5byb, a-eid, sledorze, sinclairzx81, davojan, acid-chicken, linonetwo, RyanCavanaugh, and 52 more reacted with thumbs up emoji benschac, worstpractice, and fonesti reacted with laugh emoji suchipi, fvilante, benschac, niieani, Adjective-Object, jcalz, mkosir, nokazn, anuraghazra, emily-curry, and 9 more reacted with hooray emoji alexrock, r-cyr, pfgray, whzx5byb, a-eid, sledorze, TarikGul, belgattitude, minedeljkovic, tsofist, and 24 more reacted with heart emoji whzx5byb, harrysolovay, a-eid, sledorze, Igorbek, fvilante, benschac, niieani, michal-minich, mkosir, and 12 more reacted with rocket emoji whzx5byb, tonivj5, nnnnoel, a-eid, sledorze, nirtamir2, rtrembecky, fvilante, benschac, ArnaudBarre, and 6 more reacted with eyes emoji
All reactions
  • 👍 62 reactions
  • 😄 3 reactions
  • 🎉 19 reactions
  • ❤️ 34 reactions
  • 🚀 22 reactions
  • 👀 16 reactions
Anders Hejlsberg (ahejlsberg) added 11 commits March 10, 2022 09:58
@ahejlsberg
Simplify getVariancesWorker and associated logic
55d0ee4
@ahejlsberg
Accept new API baselines
24f2dcf
@ahejlsberg
Add 'in' and 'out' modififers / add modifiers to type parameters
5f1c56e
@ahejlsberg
Check variance annotations
8dfc96f
@ahejlsberg
Update test runner
7793ec4
@ahejlsberg
Accept new API baselines
8e67c07
@ahejlsberg
Allow variance annotations only on certain type parameters
a77735d
@ahejlsberg
Add deprecated implementation of createTypeParameterDeclaration
aa6933f
@ahejlsberg
Accept new API baselines
e95f4af
@ahejlsberg
Report variance markers as 'sub-XXX' and 'super-XXX'
05ad13a
@ahejlsberg
Add tests
3799524
@typescript-bot TypeScript Bot (typescript-bot) assigned Anders Hejlsberg (ahejlsberg) Mar 13, 2022
@typescript-bot TypeScript Bot (typescript-bot) added Author: Team For Uncommitted Bug PR for untriaged, rejected, closed or missing bug labels Mar 13, 2022
@ahejlsberg

Anders Hejlsberg (ahejlsberg) commented Mar 13, 2022

Copy link
Copy Markdown
Member Author

TypeScript Bot (@typescript-bot) test this
TypeScript Bot (@typescript-bot) user test this inline
TypeScript Bot (@typescript-bot) run dt
TypeScript Bot (@typescript-bot) perf test faster

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@typescript-bot

TypeScript Bot (typescript-bot) commented Mar 13, 2022 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Contributor

Heya Anders Hejlsberg (@ahejlsberg), I've started to run the abridged perf test suite on this PR at 3799524. You can monitor the build here.

Update: The results are in!

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@typescript-bot

TypeScript Bot (typescript-bot) commented Mar 13, 2022 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Contributor

Heya Anders Hejlsberg (@ahejlsberg), I've started to run the parallelized Definitely Typed test suite on this PR at 3799524. You can monitor the build here.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@typescript-bot

TypeScript Bot (typescript-bot) commented Mar 13, 2022 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Contributor

Heya Anders Hejlsberg (@ahejlsberg), I've started to run the extended test suite on this PR at 3799524. You can monitor the build here.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@typescript-bot

TypeScript Bot (typescript-bot) commented Mar 13, 2022 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Contributor

Heya Anders Hejlsberg (@ahejlsberg), I've started to run the diff-based community code test suite on this PR at 3799524. You can monitor the build here.

Update: The results are in!

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@typescript-bot

TypeScript Bot (typescript-bot) commented Mar 13, 2022

Copy link
Copy Markdown
Contributor

Anders Hejlsberg (@ahejlsberg)
The results of the perf run you requested are in!

Here they are:

Comparison Report - main..48240

Metric main 48240 Delta Best Worst
Angular - node (v14.15.1, x64)
Memory used 332,434k (± 0.01%) 332,458k (± 0.00%) +23k (+ 0.01%) 332,425k 332,481k
Parse Time 2.03s (± 0.68%) 2.03s (± 0.55%) -0.00s (- 0.25%) 2.01s 2.05s
Bind Time 0.87s (± 0.55%) 0.87s (± 0.64%) +0.00s (+ 0.12%) 0.85s 0.88s
Check Time 5.59s (± 0.50%) 5.59s (± 0.36%) +0.01s (+ 0.13%) 5.55s 5.64s
Emit Time 6.29s (± 0.66%) 6.27s (± 0.33%) -0.03s (- 0.44%) 6.23s 6.32s
Total Time 14.78s (± 0.40%) 14.75s (± 0.23%) -0.03s (- 0.18%) 14.67s 14.82s
Compiler-Unions - node (v14.15.1, x64)
Memory used 193,349k (± 0.68%) 193,474k (± 0.60%) +126k (+ 0.07%) 191,863k 195,183k
Parse Time 0.86s (± 0.68%) 0.86s (± 0.80%) -0.00s (- 0.12%) 0.84s 0.87s
Bind Time 0.55s (± 0.67%) 0.56s (± 0.53%) +0.00s (+ 0.54%) 0.55s 0.56s
Check Time 7.43s (± 0.86%) 7.42s (± 0.60%) -0.02s (- 0.22%) 7.31s 7.50s
Emit Time 2.51s (± 1.48%) 2.52s (± 2.05%) +0.01s (+ 0.44%) 2.45s 2.69s
Total Time 11.35s (± 0.77%) 11.35s (± 0.73%) -0.00s (- 0.03%) 11.23s 11.58s
Monaco - node (v14.15.1, x64)
Memory used 325,407k (± 0.01%) 325,416k (± 0.00%) +9k (+ 0.00%) 325,376k 325,449k
Parse Time 1.57s (± 0.46%) 1.57s (± 0.68%) -0.00s (- 0.06%) 1.56s 1.61s
Bind Time 0.78s (± 0.98%) 0.78s (± 0.61%) +0.00s (+ 0.26%) 0.76s 0.78s
Check Time 5.46s (± 0.31%) 5.49s (± 0.45%) +0.03s (+ 0.59%) 5.44s 5.54s
Emit Time 3.32s (± 0.49%) 3.31s (± 0.51%) -0.01s (- 0.27%) 3.27s 3.35s
Total Time 11.12s (± 0.22%) 11.14s (± 0.27%) +0.02s (+ 0.22%) 11.07s 11.19s
TFS - node (v14.15.1, x64)
Memory used 288,853k (± 0.01%) 288,847k (± 0.01%) -6k (- 0.00%) 288,814k 288,894k
Parse Time 1.31s (± 1.46%) 1.31s (± 1.25%) -0.00s (- 0.23%) 1.28s 1.35s
Bind Time 0.73s (± 0.79%) 0.74s (± 0.88%) +0.01s (+ 1.10%) 0.73s 0.75s
Check Time 5.12s (± 0.56%) 5.12s (± 0.64%) -0.00s (- 0.08%) 5.06s 5.20s
Emit Time 3.50s (± 2.10%) 3.52s (± 1.78%) +0.02s (+ 0.63%) 3.40s 3.62s
Total Time 10.67s (± 0.98%) 10.69s (± 0.55%) +0.02s (+ 0.18%) 10.58s 10.82s
material-ui - node (v14.15.1, x64)
Memory used 453,748k (± 0.01%) 453,653k (± 0.01%) -95k (- 0.02%) 453,578k 453,702k
Parse Time 1.85s (± 0.63%) 1.85s (± 0.50%) +0.00s (+ 0.05%) 1.83s 1.87s
Bind Time 0.70s (± 0.84%) 0.71s (± 0.70%) +0.00s (+ 0.28%) 0.69s 0.71s
Check Time 20.61s (± 0.86%) 20.40s (± 0.68%) -0.22s (- 1.05%) 20.24s 20.93s
Emit Time 0.00s (± 0.00%) 0.00s (± 0.00%) 0.00s ( NaN%) 0.00s 0.00s
Total Time 23.17s (± 0.74%) 22.96s (± 0.61%) -0.21s (- 0.91%) 22.80s 23.50s
xstate - node (v14.15.1, x64)
Memory used 535,121k (± 0.01%) 535,273k (± 0.01%) +152k (+ 0.03%) 535,202k 535,328k
Parse Time 2.57s (± 0.51%) 2.56s (± 0.39%) -0.00s (- 0.00%) 2.54s 2.59s
Bind Time 1.15s (± 0.78%) 1.15s (± 0.77%) +0.00s (+ 0.09%) 1.13s 1.16s
Check Time 1.50s (± 0.53%) 1.50s (± 0.75%) -0.00s (- 0.07%) 1.48s 1.52s
Emit Time 0.07s (± 0.00%) 0.07s (± 0.00%) 0.00s ( 0.00%) 0.07s 0.07s
Total Time 5.28s (± 0.42%) 5.30s (± 0.30%) +0.01s (+ 0.25%) 5.25s 5.32s
System
Machine Namets-ci-ubuntu
Platformlinux 4.4.0-210-generic
Architecturex64
Available Memory16 GB
Available Memory4 GB
CPUs4 × Intel(R) Core(TM) i7-4770 CPU @ 3.40GHz
Hosts
  • node (v14.15.1, x64)
Scenarios
  • Angular - node (v14.15.1, x64)
  • Compiler-Unions - node (v14.15.1, x64)
  • Monaco - node (v14.15.1, x64)
  • TFS - node (v14.15.1, x64)
  • material-ui - node (v14.15.1, x64)
  • xstate - node (v14.15.1, x64)
Benchmark Name Iterations
Current 48240 10
Baseline main 10

Developer Information:

Download Benchmark

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@typescript-bot

TypeScript Bot (typescript-bot) commented Mar 13, 2022

Copy link
Copy Markdown
Contributor

Anders Hejlsberg (@ahejlsberg)
Great news! no new errors were found between main..refs/pull/48240/merge

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

This was referenced Mar 13, 2022
Always fully compute variance structurally #48080
Closed
Check order dependence with mutually-recursive non-unary generics #44572
Closed
@ahejlsberg Anders Hejlsberg (ahejlsberg) added this to the TypeScript 4.7.0 milestone Mar 13, 2022
@ahejlsberg
Anders Hejlsberg (ahejlsberg) requested review from Daniel Rosenwasser (DanielRosenwasser), Ryan Cavanaugh (RyanCavanaugh) and Wesley Wigham (weswigham) March 13, 2022 23:01
@Andarist

Mateusz Burzyński (Andarist) commented Mar 13, 2022

Copy link
Copy Markdown
Contributor

In here it has been mentioned that:

For now, we'll have to accept that variance measurement for circular types is sometimes inaccurate and/or dependent on declaration order

So from what I get - with this PR here we are going to have a somewhat unpredictable behavior by default and to make it predictable we'll be able to use variance annotations introduced by this PR. Couldn't/shouldn't the problem be flipped though? Couldn't you go with predictable and safe behavior (although slow) and propose using those variance annotations as performance optimization?

I understand that some libraries out there might be hard/slow to upgrade and to start using those annotations but with the time that should become less of a concern and people will notice great slowdowns pretty soon and they should start helping library authors to migrate to this performance optimization. With typesVersions it should be possible to support older TS versions while introducing those perf hints for 4.7.

I'm worried that by accepting the random behavior now the community will get stuck with it forever - while if this would be treated as a perf optimization then most people would get great safety improvements immediately and out of the box.

ctjlewis reacted with heart emoji
All reactions
  • ❤️ 1 reaction

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@Andarist

Mateusz Burzyński (Andarist) commented Mar 14, 2022

Copy link
Copy Markdown
Contributor

Correct me if Im wrong but in here:

Likewise, attempting to mark T invariant

It should be “contravariant”

When variance annotations are present, the type checker doesn't need to measure variance.

hm, how measuring is different from what u check and for what u raise errors described in the thread? Since reporting “correct” errors would require full structural computation - shouldnt this be described here as a limitation for raising those errors? I mean - sometimes they just wont be raised and u will trust the user input, did i get this right?

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@ahejlsberg

Anders Hejlsberg (ahejlsberg) commented Mar 14, 2022 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Member Author

Couldn't you go with predictable and safe behavior (although slow)

We considered it and we don't think it's feasible. An unknown number of code bases out there would be negatively impacted, in some cases quite dramatically. To wit, compilation of immutable.js slowed down 50x with the candidate PR. It's an awful experience when updating to the latest version of TypeScript all of a sudden hangs your build process. I'd love to do better, but for the moment we don't have other candidate solutions.

Also, it really is relatively rare that the current implementation gets variance measurement wrong. It requires types to be circularly dependent and to flip variance somewhere in the circularity. That happens, but it definitely isn't common.

I'm worried that by accepting the random behavior now the community will get stuck with it forever

The scenarios in which the issue occurs are rare and well understood, and we'll continue to think about ways in which we can improve accuracy of variance measurement without adversely affecting performance. Nothing prevents us from adopting a better algorithm in the future.

It should be “contravariant”

Indeed. Thanks for catching that, I have fixed it.

how measuring is different from what u check and for what u raise errors described in the thread?

Variance measurement is similar to variance annotation checking, but requires more checks. Specifically, we always perform at least two checks (subtype-to-supertype and supertype-to-subtype) to measure variance, and sometimes require a third check to distinguish bivariance from unwitnessed type parameters. In contrast, annotation checking requires only one check for co- or contravariance, and no check at all for invariance.

c69-addepar reacted with heart emoji
All reactions
  • ❤️ 1 reaction

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@ahejlsberg

Anders Hejlsberg (ahejlsberg) commented Apr 5, 2022 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Member Author

It seems variance annotations are ignored even when checking the same generic type

Yeah, variance annotations are only consulted when relating instantiations of type aliases for object, function, and constructor type literals and mapped types, so it is kind of meaningless to add variances annotations for other kinds of types. I think the best course of action is for us to error on attempts to do so. I will put up a PR to that effect.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@shigma Shigma (shigma) mentioned this pull request Apr 6, 2022
Suggestion: Const contexts for generic type inference #30680
Closed
5 tasks done
@ahejlsberg Anders Hejlsberg (ahejlsberg) mentioned this pull request Apr 6, 2022
Permit type alias variance annotations only for certain object types #48589
Merged
@Jack-Works

Jack Works (Jack-Works) commented Apr 9, 2022

Copy link
Copy Markdown
Contributor

image

this is interesting

wdoug, Beraliv, and Mayandev reacted with eyes emoji
All reactions
  • 👀 3 reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@ariccio

Alexander Riccio (ariccio) commented Apr 10, 2022

Copy link
Copy Markdown

I'm just dropping by to wonder if whoever came up with this was a C programmer back in the day who loved SAL? Because I sense a bit of SAL here 😉☺️

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@mikearnaldi

Michael Arnaldi (mikearnaldi) commented Apr 11, 2022

Copy link
Copy Markdown
Contributor

It seems variance annotations are ignored even when checking the same generic type

Yeah, variance annotations are only consulted when relating instantiations of type aliases for object, function, and constructor type literals and mapped types, so it is kind of meaningless to add variances annotations for other kinds of types. I think the best course of action is for us to error on attempts to do so. I will put up a PR to that effect.

Checking after diagnostics have been added it seems that it is still possible to define a parameter invariant even if the measured variance is either covariant or contravariant. Is this intended? It seems to me that given annotations are ignored in structural comparisons the only thing that make sense is to have them being strictly equal to the measured one

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@IllusionMH

Andrii Dieiev (IllusionMH) commented Apr 11, 2022

Copy link
Copy Markdown
Contributor

it is still possible to define a parameter invariant even if the measured variance is either covariant or contravariant. Is this intended?

Yes it's explicitly stated in OP

Invariance annotations (in out T) are never checked but simply assumed to hold. Thus, it is possible to assert invariance even when the actual usage of a type parameter is co- or contravariant.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@mikearnaldi

Michael Arnaldi (mikearnaldi) commented Apr 11, 2022

Copy link
Copy Markdown
Contributor

it is still possible to define a parameter invariant even if the measured variance is either covariant or contravariant. Is this intended?

Yes it's explicitly stated in OP

Invariance annotations (in out T) are never checked but simply assumed to hold. Thus, it is possible to assert invariance even when the actual usage of a type parameter is co- or contravariant.

Yes, I am asking if it is still intended and an explanation of why that is ok

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@RyanCavanaugh

Ryan Cavanaugh (RyanCavanaugh) commented Apr 11, 2022

Copy link
Copy Markdown
Member

Yes, I am asking if it is still intended and an explanation of why that is ok

Yes. Part of the goal here is not just correctness, but performance. For many libraries causing slowdowns during typing (as in, typing in the editor), variance measurement accounts for a very large portion of the CPU time spent, so "skipping" checks when the author tells us what the result is going to be is a big performance win. Asserting invariance specifically means there's no possible soundness gap created as a result, since only fewer relations are allowed as a result.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@mikearnaldi

Michael Arnaldi (mikearnaldi) commented Apr 11, 2022

Copy link
Copy Markdown
Contributor

Yes, I am asking if it is still intended and an explanation of why that is ok

Yes. Part of the goal here is not just correctness, but performance. For many libraries causing slowdowns during typing (as in, typing in the editor), variance measurement accounts for a very large portion of the CPU time spent, so "skipping" checks when the author tells us what the result is going to be is a big performance win. Asserting invariance specifically means there's no possible soundness gap created as a result, since only fewer relations are allowed as a result.

Thanks! I have definitely felt the pain in some scenarios, I agree there is no soundness gap from the structural perspective, there may be a perceived soundness gap when those annotations are ignored in structural fallback if there is a mismatch between the annotated variance and the actual variance but if the library authors are aware of it perf wins

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

David Glasser (glasser) added a commit to apollographql/apollo-server that referenced this pull request Apr 11, 2022
@glasser
Move Disabled plugins up a level and change some context typing
970f3c1
Two things got a bit mixed together here.

One is that we want the Disabled plugins to all be defined directly in
plugin/index.ts, so that loading ApolloServerPluginInlineTraceDisabled
does not spend time loading the protobuf library.

The other thing is that we started thinking a bit more carefully about
plugin context generics. We wrote some tests to make sure that you can
use an `ApolloServerPlugin<BaseContext>` (ie, a plugin that doesn't need
any particular fields on the context) with any `ApolloServer`, but not
vice versa. As part of getting this to work, we added another
`__forceTContextToBeContravariant`. We also noticed that it made more
sense for BaseContext to be `{}` ("an object with no particular fields")
rather than `Record<string, any>` ("an object where you can do anything
with any of its fields").

We investigated whether the new contravariance annotation coming in the
next two months in TS 4.7
(microsoft/TypeScript#48240) would allow us to
get rid of the `__forceTContextToBeContravariant` hack and the answer is
yes! However, trying `4.7.0-beta` failed for two other reasons. One is
that microsoft/TypeScript#48366 required us to
add some missing `extends` clauses, which we are doing now in this PR.
The other is that `graphql-tools` needs some fixes to work with TS4.7
which we hope they can do soon
(ardatan/graphql-tools#4381).
@Jack-Works

Jack Works (Jack-Works) commented Apr 12, 2022

Copy link
Copy Markdown
Contributor

Is TS going to emit variance annotations in .d.ts?

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@DanielRosenwasser

Daniel Rosenwasser (DanielRosenwasser) commented Apr 12, 2022

Copy link
Copy Markdown
Member

At the moment, the intent is to emit whatever you've written. If you leave a type parameter bare, we'll continue to leave it bare, which will mean that consuming modules will continue to infer the variance.

If you need to provide variance annotations for newer users, but need to provide an experience that gracefully degrades, you can use

  • typesVersions
  • downlevel-dts once Strip down variance annotations sandersn/downlevel-dts#73 is completed
All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@Jack-Works

Jack Works (Jack-Works) commented Apr 12, 2022

Copy link
Copy Markdown
Contributor

At the moment, the intent is to emit whatever you've written.

Can I add a compiler flag or something to let typescript emit those variance annotations in .d.ts so it will automatically speed up the compilation?

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@Andarist

Mateusz Burzyński (Andarist) commented Apr 12, 2022

Copy link
Copy Markdown
Contributor

Can I add a compiler flag or something to let typescript emit those variance annotations in .d.ts so it will automatically speed up the compilation?

Do you mean emitting the computed variance annotations?

Jack-Works reacted with thumbs up emoji
All reactions
  • 👍 1 reaction

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@weswigham

Wesley Wigham (weswigham) commented Apr 12, 2022 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Member

The computed variances are more often than not much more complicated than the simple in/out/in out the annotations expose (mapped types and conditional types have odd assignability relationships!), and since writing a variance annotation that doesn't exactly match the measured variance can lead to surprising behavior, we leave it to users to annotate as they see necessary, and make that tradeoff consciously.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@Andarist

Mateusz Burzyński (Andarist) commented Apr 12, 2022

Copy link
Copy Markdown
Contributor

mapped types and conditional types have odd assignability relationships!

Would love to read a write-up about this! It could demystify some bits about the TS compiler for a lot of people

tonivj5, A-Babin, Beraliv, 1valdis, and millsp reacted with thumbs up emoji tonivj5 reacted with eyes emoji
All reactions
  • 👍 5 reactions
  • 👀 1 reaction

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@azu azu (azu) mentioned this pull request Apr 13, 2022
2022-04-13のJS: TypeScript 4.7 Beta、RedwoodJS 1.0、Sanitizer API jser/jser.github.io#975
Merged
@benschac

benjamin (benschac) commented Apr 22, 2022

Copy link
Copy Markdown

Should using the covariance out keyword to make the generic assigned to a property readonly?

Example:

  • Flow: https://flow.org/try/#0C4TwDgpgBAyg9gWwsAFgSwHYHMoF4oDeAUFFAPRlQAqK0ARANR1QCGGGcwLwacGUtAE7QkbAM5RU0MILiRBoKGgnCWAEwC0fADYgSUBiwBcUMcEGYsAGiIBfANxFQkWImTpsAUW1jo+YqSGJmYW2FAAPlAYAK4IAEYQgjYOREQAxnxmkh5YJvBIqJZ4hKwmdLTa2nDMKRRQAGJVAO6slXBNElKsYmJoWBhIGMBR7VAJaSzRvlAABvnult6+M0R1ykoYahAQaqym0XHO0HAAZrPzhdgzI00AhOmZw5xCeW6XWEt+2ZaOq5QAQtFhhwWo1Rk00JUoIlZIIoHxWBgQN1ev1BsNgHBZiwZjY6r0MGloGhgAByCRiaJgMBwXy7TFjaAsKCqTQ6ZEyOSJUBEZ6JAB0zPwAFZ7EA

a is covariant and cannot be assigned to a number, or anything.

  • Typescript: https://www.typescriptlang.org/play?#code/C4TwDgpgBAyg9gWwsAFgSwHYHMoF4oDeAUFFAIYBcUAzsAE6ZYA0RAvgNxGiSyLLrYAogBtq0fMVKUa9RlAA+UDAFcEAIwh0WHIkQDGcDLSipGVeElPY8hclQBEKCMOFx7UHQaPAocVJvM+KywRMRtgziIAeiioAEFqajQsDDlgOCgAAz8nOkzyUQykMiNyROTU63Ss4Mzo2IAhZR9M4IA6Mny0ahplMDA4MQATEwyNchkGbABCeqgAFXAIaj0GMB9qFDhlYRG9MmA9FBN0HooACiIczQ6bAFZ2IA

a can be assigned to a new value.

  • Typescript with optional variance: https://www.typescriptlang.org/play?ts=4.7.0-dev.20220421#code/C4TwDgpgBAyg9gWwsAFgSwHYHMoF4oDeAUFFAIYBcUAzsAE6ZYA0RAvgNxGiSyLLrYAogBtqEADxwArsCgAVAHx5CJclTksORIgGM4GWlFSMq8JMezKCaqACIUEYcLi2oWvQdlxUEOqb4WWCJi4rQMlgA+UBhSCABGvkr4gZxEAPRpUACC1NRoWBiMRnBQAAbeDnSl5KIlSGQG5Ln5hZbAJaWBpemZAEIyZYEAdGTVaNQ0UmBgcGIAJsVQCeQ09IwAhD3y4BDUOgxgstQo0sILOmTAOihG6BMUABREFb4jygCs7EA

a can be assigned to a new value.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

Sheetal Nandi (sheetalkamat) added a commit to microsoft/TypeScript-TmLanguage that referenced this pull request May 24, 2022
@sheetalkamat
Support Variance Annotations
1d5a44a
Fixes microsoft/TypeScript#48240
@Jym77 Jean-Yves Moyen (Jym77) mentioned this pull request Jul 28, 2022
[api-extractor] parsing error on (infer T extends U) pattern microsoft/rushstack#3486
Closed
@KotlinIsland KotlinIsland mentioned this pull request Aug 4, 2022
PEP 695: Fix/improve syntax & content of Language Survey section python/peps#2725
Merged
@SimoneGianni Simone Gianni (SimoneGianni) mentioned this pull request Aug 20, 2022
check with explicit type signature gives error on is.object.matching with a partial object SimoneGianni/tsMatchers#17
Open
@masaeedu Asad Saeeduddin (masaeedu) mentioned this pull request Mar 12, 2023
Couple apparent bugs with variance checking #53210
Open
@whzx5byb whzx5byb mentioned this pull request Apr 16, 2023
Class inheritance should not bypass generic parameter contravariance #53798
Closed
@jedwards1211

Andy Edwards (jedwards1211) commented Jun 2, 2023 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown

I just realized, there's no way to mark a parameter bivariant to skip variance measurements on types with bivariant parameters. Is there a fundamental reason variance measurement can't be avoided when there's a bivariant parameter, or would explicit variance annotations be a reasonable feature request?

Maybe I misunderstand but it seems like the only hope of reliably avoiding potentially infinite type errors with complex circular types is to explicitly annotate every type parameter so that TS won't perform variance measurement and we know there's no risk of accidentally crossing the threshold with slightly more complex types. So I wish I could also explicitly annotate bivariance.

I'm pretty sure I wasn't thinking and parameters aren't allowed to be bivariant...I was experimenting with adding variance annotations to ZodObject and have errors making the shape parameter parameter covariant, contravariant, and invariant, so I mistakenly assumed it needs to be bivariant but I must have needed to fix something else.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@whzx5byb whzx5byb mentioned this pull request Sep 1, 2023
Covariance, contravariance and assignability #55603
Closed
@fatcerberus Bruce Pascoe (fatcerberus) mentioned this pull request Sep 29, 2023
Variance Annotations do not impact "infer" correctly #55920
Closed
@jxom jxom mentioned this pull request Jul 30, 2024
refactor: add explicit annotations to SimulateContractReturnType wevm/viem#2557
Merged
@microsoft Microsoft (microsoft) locked as resolved and limited conversation to collaborators Oct 22, 2025
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Reviewers

@RyanCavanaugh Ryan Cavanaugh (RyanCavanaugh) RyanCavanaugh approved these changes
@DanielRosenwasser Daniel Rosenwasser (DanielRosenwasser) Awaiting requested review from DanielRosenwasser
@weswigham Wesley Wigham (weswigham) Awaiting requested review from weswigham

Uh oh!

There was an error while loading. Please reload this page.

Assignees

@ahejlsberg Anders Hejlsberg (ahejlsberg)

Labels

Author: Team For Uncommitted Bug PR for untriaged, rejected, closed or missing bug

Projects

PR Backlog
Archived in project

Milestone

TypeScript 4.7.0

Development

Successfully merging this pull request may close these issues.

Proposal: covariance and contravariance generic type arguments annotations Covariance / Contravariance Annotations

Uh oh!

There was an error while loading. Please reload this page.

15 participants

@ahejlsberg @typescript-bot @Andarist @magic-akari @mikearnaldi @weswigham @tjjfvi @RyanCavanaugh @whzx5byb @Jack-Works @ariccio @IllusionMH @DanielRosenwasser @benschac @jedwards1211
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
You are visitor 01402503 — GeezerVison does not store the pages you look up.
Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.