Skip to content

Covariance, contravariance and assignability #55603

Closed as not planned
Closed as not planned

Description

🔎 Search Terms

covariance
contravariance

🕗 Version & Regression Information

(Please suggest a better title 😅)

Recently Andrew Burgess posted a video related to covariance and contravariance, and also the in and out keywords

Noticed issue related to assignability while playing around with the code

  • This is the behavior in every version I tried

⏯ Playground Link

https://www.typescriptlang.org/play?ts=5.2.2&ssl=13&ssc=1&pln=15&pc=1#code/C4TwDgpgBAUg9gIygXigbwFBShAdgRwFcJiATAQWAC4oARAQ2AgG4spgAne3AZ3oGNgASzi4AkqRo9OQ3AHNW2XPQC2EKTPmsAvqwyhIUAAocRp0PCSpLUAGTo2YU3HMganYoqgAbCADcIbxoARigAHygAJnCoAGYdPQNoAEViYgAeGAA+FAdsPCISdSgACgArGhgAShQcvzghUi85CGBLGhLGjVN5GuQcmC8AeiGcAjSIcsqqmnrG4dGWtsROyShpHrkZ2ASMDFIIfm96Dmh+UWkoMsRUoppbjMss1gOjk7OL4CgnMyELG4m9wm6RMv3+CGee3OvC++FiQKKmUQOVQ1wQDxYGGhl3wABYEY9kbkfi4-iBLBi9NjYQBWAkQEHOVxPXJoylYz5QfAANnpjLB5KJqBJzIBRVYQA

💻 Code

type Job = {
  enqueuedAt: Date;
  transactionId: string;
  name: string;
};

type PriorityJob = Job & {
  priority: true;
  level: 1 | 2 | 3;
};

type Queue<J> = {
  enqueue: (j: J) => void;
  getJob: (id: string) => J;
  // enqueue(j: J): void;
  // getJob(id: string): J;
};

declare const jobQueue: Queue<Job>;
declare const priorityJobQueue: Queue<PriorityJob>;

const q3: Queue<Job> = jobQueue;
const q4: Queue<Job> = priorityJobQueue;

const q5: Queue<PriorityJob> = jobQueue;
const q6: Queue<PriorityJob> = priorityJobQueue;

🙁 Actual behavior

If the methods defined in the Queue type (without using in and out keywords) used the arrow function syntax, there are two of the four assignments which are errors.
But if using the normal function syntax, only one is erroring.

🙂 Expected behavior

Consistent behaviour is expected in all cases.

Additional information about the issue

No response

Activity

  1. changed the title [-]Covariance contravariance and assignability[/-] [+]Covariance, contravariance and assignability[/+] on Sep 1, 2023
  2. fatcerberus commented on Sep 1, 2023

    @fatcerberus

    Methods are intentionally bivariant, this is mentioned in the FAQ:
    https://github.com/microsoft/TypeScript/wiki/FAQ#common-bugs-that-arent-bugs

    Methods are always bivariant in their argument, while function properties are contravariant in their argument under strictFunctionTypes. More discussion here.

    And from the linked issue:

    Methods are excluded specifically to ensure generic classes and interfaces (such as Array<T>) continue to mostly relate covariantly. The impact of strictly checking methods would be a much bigger breaking change as a large number of generic types would become invariant (even so, we may continue to explore this stricter mode).

  3. aswinsvijay commented on Sep 1, 2023

    @aswinsvijay
    Author

    Agreed. But then, in the latter case, the missing error pops back up when the generic is specified to be in out.
    Does that mean those keywords override bivariance 🤔 ?

  4. whzx5byb commented on Sep 1, 2023

    @whzx5byb

    Aswin S Vijay (@aswinsvijay)

    Don't rely too much on these variance annotations, as they may produce unexpected behavior when fall back to structure checking. You can see the discussion here.

  5. andrewbranch commented on Sep 1, 2023

    @andrewbranch
    Member

    Does that mean those keywords override bivariance

    Yes.

  6. typescript-bot commented on Sep 4, 2023

    @typescript-bot
    Contributor

    This issue has been marked as "Working as Intended" and has seen no recent activity. It has been automatically closed for house-keeping purposes.

  7. locked as resolved and limited conversation to collaborators on Oct 22, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Working as IntendedThe behavior described is the intended behavior; this is not a bug

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions