{"action":"created","issue":{"url":"https://api.github.com/repos/Microsoft/TypeScript/issues/11929","repository_url":"https://api.github.com/repos/Microsoft/TypeScript","labels_url":"https://api.github.com/repos/Microsoft/TypeScript/issues/11929/labels{/name}","comments_url":"https://api.github.com/repos/Microsoft/TypeScript/issues/11929/comments","events_url":"https://api.github.com/repos/Microsoft/TypeScript/issues/11929/events","html_url":"https://github.com/Microsoft/TypeScript/pull/11929","id":186041340,"number":11929,"title":"Static types for dynamically named properties","user":{"login":"ahejlsberg","id":4226954,"avatar_url":"https://avatars.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},"labels":[{"id":164593272,"url":"https://api.github.com/repos/Microsoft/TypeScript/labels/cla-not-required","name":"cla-not-required","color":"009800","default":false}],"state":"closed","locked":false,"assignee":null,"assignees":[],"milestone":null,"comments":7,"created_at":"2016-10-28T23:13:08Z","updated_at":"2016-11-02T16:51:41Z","closed_at":"2016-11-02T16:36:55Z","pull_request":{"url":"https://api.github.com/repos/Microsoft/TypeScript/pulls/11929","html_url":"https://github.com/Microsoft/TypeScript/pull/11929","diff_url":"https://github.com/Microsoft/TypeScript/pull/11929.diff","patch_url":"https://github.com/Microsoft/TypeScript/pull/11929.patch"},"body":"This PR adds new typing constructs that enable static validation of code involving dynamic property names and properties selected by such dynamic names. For example, in JavaScript it is fairly common to have APIs that expect property names as parameters, but so far it hasn't been possible to express the type relationships that occur in those APIs. The PR also improves error messages related to missing properties and/or index signatures.\r\n\r\nThe PR is inspired by #1295 and #10425 and the discussions in those issues. The PR implements two new type constructs:\r\n- _Index type queries_ of the form `keyof T`, where `T` is some type.\r\n- _Indexed access types_ of the form `T[K]`, where `T` is some type and `K` is a type that is assignable to `keyof T`.\r\n\r\nAn index type query `keyof T` yields the type of permitted index values for `T`. When `T` is not a type parameter, `keyof T` is resolved as follows:\r\n- If `T` has no apparent index signatures, `keyof T` is a type of the form `\"p1\" | \"p2\" | ... | \"pX\"`, where the string literals represent the names of the public properties of `T`. If `T` has no public properties, `keyof T` is the type `never`.\r\n- If T has an apparent numeric index signature but no apparent string index signature, `keyof T` is a union of the public property names of `T` and the type `number`.\r\n- If `T` has an apparent string index signature, `keyof T` is the type `string | number`.\r\n\r\nAn indexed access type `T[K]` requires `K` to be a type that is assignable to `keyof T` and yields the type of the property or properties in `T` selected by `K`. `T[K]` permits `K` to be a type parameter, in which case `K` must be constrained to a type that is assignable to `keyof T`. Otherwise, when `K` is not a type parameter, `T[K]` is resolved as follows:\r\n- If `K` is a union type `K1 | K2 | ... | Kn`, `T[K]` is equivalent to `T[K1] | T[K2] | ... | T[Kn]`.\r\n- If `K` is a string literal type, numeric literal type, or enum literal type and `T` contains a public property with the name given by that literal type, `T[K]` is the type of that property.\r\n- If `K` is a type assignable to `number` and `T` contains a numeric index signature, `T[K]` is the type of that numeric index signature.\r\n- If `K` is a type assignable to `string` or `number` and `T` contains a string index signature, `T[K]` is the type of that string index signature.\r\n\r\nSome examples:\r\n\r\n``` ts\r\ninterface Thing {\r\n    name: string;\r\n    width: number;\r\n    height: number;\r\n    inStock: boolean;\r\n}\r\n\r\ntype K1 = keyof Thing;  // \"name\" | \"width\" | \"height\" | \"inStock\"\r\ntype K2 = keyof Thing[];  // number | \"length\" | \"push\" | \"pop\" | \"concat\" | ...\r\ntype K3 = keyof { [x: string]: Thing };  // string | number\r\n\r\ntype P1 = Thing[\"name\"];  // string\r\ntype P2 = Thing[\"width\" | \"height\"];  // number\r\ntype P3 = Thing[\"name\" | \"inStock\"];  // string | boolean\r\ntype P4 = string[\"charAt\"];  // (pos: number) => string\r\ntype P5 = string[][\"push\"];  // (...items: string[]) => number\r\n```\r\n\r\nAn indexed access type `T[K]` permits `K` to be a type parameter that is constrained to `keyof T`. This makes it possible to do parametric abstraction over property access:\r\n\r\n``` ts\r\nfunction getProperty<T, K extends keyof T>(obj: T, key: K) {\r\n    return obj[key];  // Inferred type is T[K]\r\n}\r\n\r\nfunction setProperty<T, K extends keyof T>(obj: T, key: K, value: T[K]) {\r\n    obj[key] = value;\r\n}\r\n\r\nfunction f1(thing: Thing, propName: \"name\" | \"width\") {\r\n    let name = getProperty(thing, \"name\");  // Ok, type string\r\n    let size = getProperty(thing, \"size\");  // Error, no property named \"size\"\r\n    setProperty(thing, \"width\", 42);  // Ok\r\n    setProperty(thing, \"color\", \"blue\");  // Error, no property named \"color\"\r\n    let nameOrWidth = getProperty(thing, propName);  // Ok, type string | number\r\n}\r\n\r\nfunction f2(things: Thing[], x: number) {\r\n    let length = getProperty(things, \"length\");  // Ok, type number\r\n    let t0 = getProperty(things, 0);  // Ok, type Thing\r\n    let t1 = getProperty(things, 1);  // Ok, type Thing\r\n    let tX = getProperty(things, x);  // Ok, type Thing\r\n}\r\n\r\nclass Component<PropType> {\r\n    props: PropType;\r\n    getProperty<K extends keyof PropType>(key: K) {\r\n        return this.props[key];\r\n    }\r\n    setProperty<K extends keyof PropType>(key: K, value: PropType[K]) {\r\n        this.props[key] = value;\r\n    }\r\n}\r\n\r\nfunction f3(component: Component<Thing>) {\r\n    let width = component.getProperty(\"width\");  // Ok, type number\r\n    component.setProperty(\"name\", \"test\");  // Ok\r\n}\r\n\r\nfunction pluck<T, K extends keyof T>(array: T[], key: K) {\r\n    return array.map(x => x[key]);\r\n}\r\n\r\nfunction f4(things: Thing[]) {\r\n    let names = pluck(things, \"name\");  // string[]\r\n    let widths = pluck(things, \"width\");  // number[]\r\n}\r\n```"},"comment":{"url":"https://api.github.com/repos/Microsoft/TypeScript/issues/comments/257926047","html_url":"https://github.com/Microsoft/TypeScript/pull/11929#issuecomment-257926047","issue_url":"https://api.github.com/repos/Microsoft/TypeScript/issues/11929","id":257926047,"user":{"login":"mhegazy","id":8000722,"avatar_url":"https://avatars.githubusercontent.com/u/8000722?v=3","gravatar_id":"","url":"https://api.github.com/users/mhegazy","html_url":"https://github.com/mhegazy","followers_url":"https://api.github.com/users/mhegazy/followers","following_url":"https://api.github.com/users/mhegazy/following{/other_user}","gists_url":"https://api.github.com/users/mhegazy/gists{/gist_id}","starred_url":"https://api.github.com/users/mhegazy/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mhegazy/subscriptions","organizations_url":"https://api.github.com/users/mhegazy/orgs","repos_url":"https://api.github.com/users/mhegazy/repos","events_url":"https://api.github.com/users/mhegazy/events{/privacy}","received_events_url":"https://api.github.com/users/mhegazy/received_events","type":"User","site_admin":false},"created_at":"2016-11-02T16:51:41Z","updated_at":"2016-11-02T16:51:41Z","body":"@jods4 you bring a good point. this is not supported now. do you mind logging a different issue to track this."}}
{"actor":{"display_login":"mhegazy"}}