{"action":"created","issue":{"url":"https://api.github.com/repos/Microsoft/TypeScript/issues/10717","repository_url":"https://api.github.com/repos/Microsoft/TypeScript","labels_url":"https://api.github.com/repos/Microsoft/TypeScript/issues/10717/labels{/name}","comments_url":"https://api.github.com/repos/Microsoft/TypeScript/issues/10717/comments","events_url":"https://api.github.com/repos/Microsoft/TypeScript/issues/10717/events","html_url":"https://github.com/Microsoft/TypeScript/issues/10717","id":175152655,"number":10717,"title":"Proposal: covariance and contravariance generic type arguments annotations","user":{"login":"Igorbek","id":1929486,"avatar_url":"https://avatars1.githubusercontent.com/u/1929486?v=3","gravatar_id":"","url":"https://api.github.com/users/Igorbek","html_url":"https://github.com/Igorbek","followers_url":"https://api.github.com/users/Igorbek/followers","following_url":"https://api.github.com/users/Igorbek/following{/other_user}","gists_url":"https://api.github.com/users/Igorbek/gists{/gist_id}","starred_url":"https://api.github.com/users/Igorbek/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Igorbek/subscriptions","organizations_url":"https://api.github.com/users/Igorbek/orgs","repos_url":"https://api.github.com/users/Igorbek/repos","events_url":"https://api.github.com/users/Igorbek/events{/privacy}","received_events_url":"https://api.github.com/users/Igorbek/received_events","type":"User","site_admin":false},"labels":[{"id":117630560,"url":"https://api.github.com/repos/Microsoft/TypeScript/labels/In%20Discussion","name":"In Discussion","color":"556b75","default":false},{"id":113971155,"url":"https://api.github.com/repos/Microsoft/TypeScript/labels/Suggestion","name":"Suggestion","color":"006b75","default":false}],"state":"open","locked":false,"assignee":null,"assignees":[],"milestone":null,"comments":32,"created_at":"2016-09-06T03:23:07Z","updated_at":"2017-04-10T18:15:40Z","closed_at":null,"body":"I have published a proposal document that makes attempt to address an outstanding issue with type variance, that was brought and discussed at #1394 \n\nThe work is currently not complete, however the idea is understood and just needs proper wording and documenting. I would like to hear feedback from the TypeScript team and community before I waste too much :).\n\nPlease see the proposal here - https://github.com/Igorbek/TypeScript-proposals/tree/covariance/covariance, and below is a summary of the idea\n## Problem\n\nThere's a huge hole in the type system that assignability checking does not respect a contravariant nature of function input parameters:\n\n``` ts\nclass Base { public a; }\nclass Derived extends Base { public b; }\n\nfunction useDerived(derived: Derived) { derived.b; }\n\nconst useBase: (base: Base) => void = useDerived; // this must not be allowed\nuseBase(new Base());    // no compile error, runtime error\n```\n\nCurrently, [TypeScript considers input parameters _bivariant_](https://github.com/Microsoft/TypeScript-Handbook/blob/master/pages/Type%20Compatibility.md#function-parameter-bivariance).\nThat's been designed in that way to avoid too strict assignability rules that would make language use much harder. Please see [links section](#links) for argumentation from TypeScript team.\n\nThere're more problematic examples at the original discussion #1394\n## Proposal summary\n\nPlease see [proposal document](https://github.com/Igorbek/TypeScript-proposals/blob/covariance/covariance/proposal.md) for details. \n1. Strengthen input parameters assignability constraints from considering _bivariant_ to considering _contravariant_.\n2. Introduce type variance annotations (`in` and `out`) in generic type argument positions\n   1. `in` annotates _contravariant_ generic type arguments\n   2. `out` annotates _covariant_ generic type arguments\n   3. `in out` and `out in` annotate _bivariant_ generic type arguments\n   4. generic type arguments without these annotations are considered _invariant_  \n3. The annotated generic types annotated with `in` and `out` are internally represented by compiler constructed types (transformation rules are defined in the proposal)\n\nAdditionally, there're a few **optional** modifications being proposed: \n1. Allow type variance annotation (`in` and `out`) in generic type parameter positions to instruct compiler check for co/contravariance violations.\n2. Introduce write-only properties (in addition to read-only), so that contravariant counterpart of read-write property could be extracted\n3. Improve type inference system to make possible automatically infer type variance from usage\n## Details\n\nWithin a type definitions each type reference position can be considered as:\n- _covariant position_, that means for output (such as method/call/construct return types)\n- _contravariant position_, that means for input (such as input parameters)\n\nSo that when a generic type referenced with annotated type argument, a new type constructed from the original by stripping out any variance incompatibilities:\n- `write(x: T): void` is removed when `T` referenced with `out`\n- `read(): T` is reset to `read(): {}` when `T` referenced with `in`\n- `prop: T` becomes `readonly prop: T` when `T` referenced with `out`\n- ... see more details in the proposal document\n## Examples\n\nSay an interface is defined:\n\n``` ts\ninterface A<T> {\n    getName(): string;  // no generic parameter referenced\n    getNameOf(t: T): string;    // reference in input\n    whoseName(name: string): T; // reference in output\n    copyFrom(a: A<in T>): void;  // explicitly set contravariance\n    copyTo(a: A<out T>): void;   // explicitly set covariance\n    current: T;         // read-write property, both input and output\n}\n```\n\nSo that, when it's referenced as `A<out T>` or with any other annotations, the following types are actually constructed and used:\n\n``` ts\ninterface A<in T> {\n    getName(): string;  // left untouched\n    getNameOf(t: T): string;    // T is in contravariant position, left\n    whoseName(name: string): {};   // T is in covariant position, reset to {}\n    copyFrom(a: A<in T>): void;  // T is contravariant already\n    //copyTo(a: A<out T>): void; // T is covariant, removed\n    //current: T;   // T is in bivariant position, write-only could be used if it were supported \n}\n\ninterface A<out T> {\n    getName(): string;  // left untouched\n    //getNameOf(t: T): string;  // T is in contravariant position, removed\n    whoseName(name: string): T; // T is in covariant position, left \n    //copyFrom(a: A<in T>): void;  // T is contravariant, removed\n    copyTo(a: A<out T>): void;   // T is covariant, left\n    readonly current: T;    // readonly property is in covariant position \n}\n\ninterface A<in out T> {  // bivariant\n    getName(): string;  // left untouched\n    //getNameOf(t: T): string;    // T is in contravariant position, removed\n    whoseName(name: string): {};   // T is in covariant position, reset to {}\n    //copyFrom(a: A<in T>): void;  // T is contravariant, removed\n    //copyTo(a: A<out T>): void; // T is covariant, removed\n    readonly current: {};    // readonly property is in covariant position, but type is stripped out \n}\n```\n## Links\n- Original suggestion/discussion #1394\n- Stricter TypeScript #274\n- Suggestion to turn off parameter covariance #6102\n## Call for people\n\n@ahejlsberg\n@RyanCavanaugh\n@danquirk\n\n@aleksey-bykov\n@isiahmeadows\n"},"comment":{"url":"https://api.github.com/repos/Microsoft/TypeScript/issues/comments/293033843","html_url":"https://github.com/Microsoft/TypeScript/issues/10717#issuecomment-293033843","issue_url":"https://api.github.com/repos/Microsoft/TypeScript/issues/10717","id":293033843,"user":{"login":"ahejlsberg","id":4226954,"avatar_url":"https://avatars2.githubusercontent.com/u/4226954?v=3","gravatar_id":"","url":"https://api.github.com/users/ahejlsberg","html_url":"https://github.com/ahejlsberg","followers_url":"https://api.github.com/users/ahejlsberg/followers","following_url":"https://api.github.com/users/ahejlsberg/following{/other_user}","gists_url":"https://api.github.com/users/ahejlsberg/gists{/gist_id}","starred_url":"https://api.github.com/users/ahejlsberg/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ahejlsberg/subscriptions","organizations_url":"https://api.github.com/users/ahejlsberg/orgs","repos_url":"https://api.github.com/users/ahejlsberg/repos","events_url":"https://api.github.com/users/ahejlsberg/events{/privacy}","received_events_url":"https://api.github.com/users/ahejlsberg/received_events","type":"User","site_admin":false},"created_at":"2017-04-10T18:15:40Z","updated_at":"2017-04-10T18:15:40Z","body":"See #15104 for a targeted change that makes `Promise<T>` and similar types properly covariant."}}
{"actor":{"display_login":"ahejlsberg"}}