{"action":"opened","issue":{"url":"https://api.github.com/repos/Microsoft/TypeScript/issues/16036","repository_url":"https://api.github.com/repos/Microsoft/TypeScript","labels_url":"https://api.github.com/repos/Microsoft/TypeScript/issues/16036/labels{/name}","comments_url":"https://api.github.com/repos/Microsoft/TypeScript/issues/16036/comments","events_url":"https://api.github.com/repos/Microsoft/TypeScript/issues/16036/events","html_url":"https://github.com/Microsoft/TypeScript/issues/16036","id":230801727,"number":16036,"title":"Indexed access behavior differs between type aliases and type parameters.","user":{"login":"hearnden","id":944457,"avatar_url":"https://avatars0.githubusercontent.com/u/944457?v=3","gravatar_id":"","url":"https://api.github.com/users/hearnden","html_url":"https://github.com/hearnden","followers_url":"https://api.github.com/users/hearnden/followers","following_url":"https://api.github.com/users/hearnden/following{/other_user}","gists_url":"https://api.github.com/users/hearnden/gists{/gist_id}","starred_url":"https://api.github.com/users/hearnden/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/hearnden/subscriptions","organizations_url":"https://api.github.com/users/hearnden/orgs","repos_url":"https://api.github.com/users/hearnden/repos","events_url":"https://api.github.com/users/hearnden/events{/privacy}","received_events_url":"https://api.github.com/users/hearnden/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"assignees":[],"milestone":null,"comments":0,"created_at":"2017-05-23T18:27:16Z","updated_at":"2017-05-23T18:27:16Z","closed_at":null,"body":"**TypeScript Version:**  2.3.2\r\n\r\nSummary: `Tagged<Opts>[keyof Opts]` evaluates differently depending on whether `Opts` is a type alias or a type parameter.\r\n\r\n**Code**\r\n\r\n```ts\r\n// Given an index type:\r\ntype MyOpts = {\r\n  x: number,\r\n  y: string,\r\n};\r\n\r\n// pair each value with its index tag:\r\ntype Tagged<T> = { [K in keyof T]: { tag: K, val: T[K] } };\r\n// which produces:\r\n//   Tagged<MyOpts> == {\r\n//     x: { tag: 'x', val: number },\r\n//     y: { tag: 'y', val: string }\r\n//   }\r\n\r\n// Then project the signature of that mapped type to get a tagged/disjoint union:\r\ntype MyTaggedUnion1 = Tagged<MyOpts>[keyof MyOpts];\r\n// which produces:\r\n//   MyTaggedUnion1 = { tag: 'x', val: number } | { tag: 'y', val: string }\r\n// which is exactly what we want.\r\n\r\n// But when trying to express Tagged<MyOpts>[keyof MyOpts] as a generic type expression,\r\n// the result turns out to be not as specific:\r\ntype TaggedUnion<Opts> = Tagged<Opts>[keyof Opts];\r\ntype MyTaggedUnion2 = TaggedUnion<MyOpts>;\r\n// produces:\r\n//   MyTaggedUnion2 = { tag: 'x' | 'y', val: number | string }\r\n```\r\n[Playground link](https://www.typescriptlang.org/play/#src=%0D%0Atype%20Tagged%3CT%3E%20%3D%20%7B%20%5BK%20in%20keyof%20T%5D%3A%20%20%7B%20tag%3A%20K%2C%20val%3A%20T%5BK%5D%20%7D%20%7D%3B%0D%0Atype%20TaggedUnion%3COpts%3E%20%3D%20Tagged%3COpts%3E%5Bkeyof%20Opts%5D%3B%0D%0A%0D%0Atype%20MyOpts%20%3D%20%7B%0D%0A%20%20x%3A%20number%2C%0D%0A%20%20y%3A%20string%2C%0D%0A%7D%3B%0D%0A%0D%0Atype%20MyTaggedUnion1%20%3D%20Tagged%3CMyOpts%3E%5Bkeyof%20MyOpts%5D%3B%0D%0Atype%20MyTaggedUnion2%20%3D%20TaggedUnion%3CMyOpts%3E%3B%0D%0A)\r\n\r\n**Expected behavior:**\r\n`Tagged<O>[keyof O]` should produce the same thing, whether `O` is an alias to a type literal or the name of a type parameter.\r\n\r\n**Actual behavior:**\r\nThe literal version produces the desirable result:\r\n```ts\r\n{ tag: 'x', val: number } | { tag: 'y', val: string }\r\n```\r\nThe parameterized version produces the weaker result:\r\n```\r\n{ tag: 'x' | 'y', val: number | string }\r\n```\r\n\r\nPossibly related: https://github.com/Microsoft/TypeScript/issues/15983"}}
{"actor":{"display_login":"hearnden"}}