{"action":"created","issue":{"url":"https://api.github.com/repos/Microsoft/TypeScript/issues/1295","repository_url":"https://api.github.com/repos/Microsoft/TypeScript","labels_url":"https://api.github.com/repos/Microsoft/TypeScript/issues/1295/labels{/name}","comments_url":"https://api.github.com/repos/Microsoft/TypeScript/issues/1295/comments","events_url":"https://api.github.com/repos/Microsoft/TypeScript/issues/1295/events","html_url":"https://github.com/Microsoft/TypeScript/issues/1295","id":50384290,"number":1295,"title":"Suggestion: Type Property type","user":{"login":"fdecampredon","id":864201,"avatar_url":"https://avatars.githubusercontent.com/u/864201?v=3","gravatar_id":"","url":"https://api.github.com/users/fdecampredon","html_url":"https://github.com/fdecampredon","followers_url":"https://api.github.com/users/fdecampredon/followers","following_url":"https://api.github.com/users/fdecampredon/following{/other_user}","gists_url":"https://api.github.com/users/fdecampredon/gists{/gist_id}","starred_url":"https://api.github.com/users/fdecampredon/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/fdecampredon/subscriptions","organizations_url":"https://api.github.com/users/fdecampredon/orgs","repos_url":"https://api.github.com/users/fdecampredon/repos","events_url":"https://api.github.com/users/fdecampredon/events{/privacy}","received_events_url":"https://api.github.com/users/fdecampredon/received_events","type":"User","site_admin":false},"labels":[{"url":"https://api.github.com/repos/Microsoft/TypeScript/labels/Accepting%20PRs","name":"Accepting PRs","color":"009800"},{"url":"https://api.github.com/repos/Microsoft/TypeScript/labels/Suggestion","name":"Suggestion","color":"006b75"}],"state":"open","locked":false,"assignee":null,"milestone":{"url":"https://api.github.com/repos/Microsoft/TypeScript/milestones/2","html_url":"https://github.com/Microsoft/TypeScript/milestones/Community","labels_url":"https://api.github.com/repos/Microsoft/TypeScript/milestones/2/labels","id":721044,"number":2,"title":"Community","description":"Issues in the 'Community' milestone are ones which we are accepting pull requests for","creator":{"login":"RyanCavanaugh","id":6685088,"avatar_url":"https://avatars.githubusercontent.com/u/6685088?v=3","gravatar_id":"","url":"https://api.github.com/users/RyanCavanaugh","html_url":"https://github.com/RyanCavanaugh","followers_url":"https://api.github.com/users/RyanCavanaugh/followers","following_url":"https://api.github.com/users/RyanCavanaugh/following{/other_user}","gists_url":"https://api.github.com/users/RyanCavanaugh/gists{/gist_id}","starred_url":"https://api.github.com/users/RyanCavanaugh/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/RyanCavanaugh/subscriptions","organizations_url":"https://api.github.com/users/RyanCavanaugh/orgs","repos_url":"https://api.github.com/users/RyanCavanaugh/repos","events_url":"https://api.github.com/users/RyanCavanaugh/events{/privacy}","received_events_url":"https://api.github.com/users/RyanCavanaugh/received_events","type":"User","site_admin":false},"open_issues":169,"closed_issues":53,"state":"open","created_at":"2014-07-14T23:24:58Z","updated_at":"2016-02-09T04:51:36Z","due_on":null,"closed_at":null},"comments":30,"created_at":"2014-11-28T15:31:28Z","updated_at":"2016-02-09T06:46:10Z","closed_at":null,"body":"## Motivations\r\n\r\nA lot of JavaScript library/framework/pattern involve computation based on the property name of an object. For example [Backbone](http://backbonejs.org/) model, functional transformation `pluck`, [ImmutableJS](https://github.com/facebook/immutable-js) are all based on such mechanism. \r\n\r\n```JavaScript\r\n//backbone\r\nvar Contact = Backbone.Model.extend({})\r\nvar contact = new Contact();\r\ncontact.get('name');\r\ncontact.set('age', 21);\r\n\r\n// ImmutableJS\r\nvar map = Immutable.Map({ name: 'François', age: 20 });\r\nmap = map.set('age', 21);\r\nmap.get('age'); // 21\r\n\r\n//pluck\r\nvar arr = [{ name: 'François' }, { name: 'Fabien' }];\r\n_.pluck(arr, 'name') // ['François', 'Fabien'];\r\n```\r\nWe can easily understand in those examples the relation between the api and the underlying type constraint.\r\nIn the case of the backbone model, it is just a kind of *proxy* for an object of type : \r\n```typescript\r\ninterface Contact {\r\n  name: string;\r\n  age: number;\r\n}\r\n```\r\nFor the case of `pluck`, it's a transformation \r\n```\r\nT[] => U[]\r\n```\r\nwhere U is the type of a property of T `prop`.\r\n\r\nHowever we have no way to express such relation in TypeScript, and ends up with dynamic type.\r\n\r\n## Proposed solution\r\nThe proposed solution is to introduce a new syntax for type `T[prop]` where `prop` is an argument of the function using such type as return value or type parameter.\r\nWith this new type syntax we could write the following definition : \r\n\r\n```typescript\r\ndeclare module Backbone {\r\n\r\n  class Model<T> {\r\n    get(prop: string): T[prop];\r\n    set(prop: string, value: T[prop]): void;\r\n  }\r\n}\r\n\r\ndeclare module ImmutableJS {\r\n  class Map<T> {\r\n    get(prop: string): T[prop];\r\n    set(prop: string, value: T[prop]): Map<T>;\r\n  }\r\n}\r\n\r\ndeclare function pluck<T>(arr: T[], prop: string): Array<T[prop]>  // or T[prop][] \r\n```\r\n\r\nThis way, when we use our Backbone model, TypeScript could correctly type-check the `get` and `set` call.\r\n\r\n```typescript\r\ninterface Contact {\r\n  name: string;\r\n  age: number;\r\n}\r\nvar contact: Backbone.Model<Contact>;\r\n\r\nvar age = contact.get('age');\r\ncontact.set('name', 3) /// error\r\n```\r\n\r\n## The `prop` constant\r\n\r\n### Constraint\r\nObviously the constant must be of a type that can be used as  index type (`string`, `number`, `Symbol`).\r\n\r\n### Case of indexable\r\n\r\nLet's give a look at our `Map` definition: \r\n\r\n```typescript\r\ndeclare module ImmutableJS {\r\n  class Map<T> {\r\n    get(prop: string): T[string];\r\n    set(prop: string, value: T[string]): Map<T>;\r\n  }\r\n}\r\n```\r\n\r\nIf `T` is indexable, our map inherit of this behavior: \r\n```typescript\r\nvar map = new ImmutableJS.Map<{ [index: string]: number}>;\r\n```\r\nNow `get` has for type `get(prop: string): number`.\r\n\r\n## Interrogation \r\n\r\nNow There is some cases where I have pain to think of a *correct* behavior, let's start again with our `Map` definition.\r\nIf instead of passing `{ [index: string]: number }` as type parameter we would have given \r\n`{ [index: number]: number }` should the compiler raise an error ? \r\n\r\nif we use `pluck` with a dynamic expression for prop instead of a constant : \r\n```typescript\r\nvar contactArray: Contact[] = []\r\nfunction pluckContactArray(prop: string) {\r\n  return _.pluck(myArray, prop);\r\n}\r\n```\r\nor with a constant that is not a property of the type passed as parameter.\r\nshould the call to `pluck` raise an error since the compiler cannot infer the type `T[prop]`, shoud `T[prop]` be  resolved to `{}` or `any`, if so should the compiler with `--noImplicitAny` raise an error ?\r\n\r\n\r\n\r\n\r\n"},"comment":{"url":"https://api.github.com/repos/Microsoft/TypeScript/issues/comments/181733962","html_url":"https://github.com/Microsoft/TypeScript/issues/1295#issuecomment-181733962","issue_url":"https://api.github.com/repos/Microsoft/TypeScript/issues/1295","id":181733962,"user":{"login":"Artazor","id":185374,"avatar_url":"https://avatars.githubusercontent.com/u/185374?v=3","gravatar_id":"","url":"https://api.github.com/users/Artazor","html_url":"https://github.com/Artazor","followers_url":"https://api.github.com/users/Artazor/followers","following_url":"https://api.github.com/users/Artazor/following{/other_user}","gists_url":"https://api.github.com/users/Artazor/gists{/gist_id}","starred_url":"https://api.github.com/users/Artazor/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Artazor/subscriptions","organizations_url":"https://api.github.com/users/Artazor/orgs","repos_url":"https://api.github.com/users/Artazor/repos","events_url":"https://api.github.com/users/Artazor/events{/privacy}","received_events_url":"https://api.github.com/users/Artazor/received_events","type":"User","site_admin":false},"created_at":"2016-02-09T06:46:09Z","updated_at":"2016-02-09T06:46:09Z","body":"@spion I've got your point of view — you've misunderstood me (but it's my fault), by the `T[p]` I've meant an entirely different thing, and you will see that `p extends string` is a crucial thing here. Let me explain my thoughts in depth.\r\n\r\nLet's consider four use cases for data structures: `List`, `Tuple`, `Dictionary` and `Record`. We'll refer to them as _conceptual data structures_ and describe them with the following properties:\r\n<table>\r\n<tr><td rowspan=\"2\" colspan=\"2\" align=\"center\">Conceptual data structures</td><th colspan=\"2\">Access by</th></tr>\r\n<tr><th>a. position<br><sub>(number)</sub></th><th>b. key<br><sub>(string)</sub></th></tr>\r\n<tr><th rowspan=\"2\">Count of<br> items<th>1. variable<br><sub>(the same role for each item)</sub></th><td align=\"center\">List</td><td align=\"center\">Dictionary</td></tr>\r\n<tr><th>2. fixed<br><sub>(each item plays its own unique role)</sub></th><td align=\"center\">Tuple</td><td align=\"center\">Record</td></tr>\r\n</table>\r\n\r\nIn JavaScript, these four cases are backed by two storage forms: an `Array` — for **a1** and **a2**, and an `Object` — for **b1** and **b2**. \r\n> ***Note 1***.  To be honest, it is not correct to say that the `Tuple` is backed by the `Array`, as the only \"true\" tuple type is the type of the `arguments` object which is not an `Array`. Nevertheless, they are more or less interchangeable, especially in the context of the destructuring and the `Function.prototype.apply` which opens the door for the meta-programming. The TypeScript also leverages Arrays for modeling Tuples.\r\n\r\n> ***Note 2***. While the full concept of the Dictionary with arbitrary keys was introduced decades later in form of the ES6 `Map`, Brendan Eich's initial decision to conflate a `Record` and a limited `Dictionary` (with string keys only) under the same hood of `Object` (where `obj.prop` is equivalent to the `obj[\"prop\"]`) became the most controversial element of the entire language (in my opinion). \r\nIt is both the curse and the blessing of the JavaScript semantics. It makes reflection trivial and encourages programmers freely switch between _programming_ and _meta-programming_  levels at almost zero mental cost (even without noticing!). I believe it is the essential part of the JavaScript success as the scripting language.\r\n\r\nNow it is the time for the TypeScript to provide the way for expressing types for this weird semantics. When we think at the _programming_ level all is ok:\r\n\r\n<table>\r\n<tr><td rowspan=\"2\" colspan=\"2\" align=\"center\">Types at the programming level</td><th colspan=\"2\">Access by</th></tr>\r\n<tr><th>a. position<br><sub>(number)</sub></th><th>b. key<br><sub>(string)</sub></th></tr>\r\n<tr><th rowspan=\"2\">Count of<br> items<th>1. variable<br><sub>(the same role for each item)</sub></th><td align=\"center\">T[]</td><td align=\"center\">{[key:string]:T}</td></tr>\r\n<tr><th>2. fixed<br><sub>(each item plays its own unique role)</sub></th><td align=\"center\">[T1, T2, ...]</td><td align=\"center\">{key1: T1, key2: T2, ...}</td></tr>\r\n</table>\r\n\r\nHowever, when we switch to the _meta-programming_ level, then things that were fixed at the _programming_ level suddenly become variable! And here we suddenly recognize relations between tuples and function signatures and propose things like #5453 (Variadic Kinds) that in fact covers only small (but quite important) part of the metaprogramming needs — the concatenation of signatures by giving the ability to destructure a formal parameter into types of the rest-args:\r\n\r\n```TypeScript\r\n     function f<T>(a: number, ...args:T) { ... }\r\n\r\n    f<[string,boolean]>(1, \"A\", true);\r\n```\r\n\r\nIn case, if #6018 also will be implemented, the Function class could look like\r\n\r\n```TypeScript\r\ndeclare class Function<This, TArgs, TRes> {\r\n        This::(...args: TArgs): TRes;\r\n        call(self: This, ...args: TArgs): TRes;\r\n        apply(self: This, args: TArgs): TRes;\r\n        // bind needs also formal pattern matching:\r\n        bind<[...TPartial, ...TCurried] = TArgs>(\r\n           self: This, ...args: TPartial): Function<{}, TCurried, TRes> \r\n}\r\n```\r\n\r\nIt is great but anyway incomplete.\r\n\r\nFor example, imagine that we want to assign a correct type to the following function:\r\n\r\n```TypeScript\r\nfunction extractAndWrapAll(...args) {\r\n     return args.map(x => [x]);\r\n}\r\n\r\n// wrapAll(1,\"A\",true) === [[1],[\"A\"],[true]]\r\n```\r\nWith proposed variadic kinds we can't transform types of the signature. Here we need something more powerful. In fact, it is desirable to have compile-time functions that can operate over types (as in Facebook's Flow). Though, I'm sure this will be possible only when (and if) the type system of the TypeScript would be stable enough to expose it to the end programmers without significant risk to break a user-land on a next minor update. Thus, we need something less radical than the full meta-programming support but still capable of dealing with demonstrated problems.\r\n\r\nTo address this problem, I want to introduce the notion of _object signature_. Roughly it is either\r\n\r\n1. the set of the property names of the object, or\r\n2. the set of the keys of the dictionary, or\r\n3. the set of the numeric indexes of an array\r\n4. the set of numeric positions of a tuple.\r\n\r\nIdeally, it would be nice to have an integer literal types as well as string literal types to represent signatures of the arrays or tuples like\r\n\r\n```TypeScript\r\ntype ZeroToFive = 0 | 1 | 2 | 3 | 4 | 5;\r\n// or\r\ntype ZeroToFive = 0 .. 5;   // ZeroToFive extends number (!)\r\n```\r\nthe rules for integer literals are congruent to the string literal ones;\r\n\r\nThen we can introduce signature abstraction syntax, that exactly matches to the object rest/spread syntax:\r\n\r\n```TypeScript\r\n{...Props: T }\r\n```\r\n\r\nwith one significant exception: here `Props` is the identifier that is bound under the universal quantifier:\r\n\r\n```TypeScript\r\n<Props extends string> {...Props: T }  // every property has type T\r\n```\r\n\r\n```TypeScript\r\n<Index extends number> {...Index: T }  // every item has type T  \r\n// the same as T[]\r\n```\r\n\r\nthus, it is introduced in type lexical scope and can be used anywhere in this scope as the name of the type. However, its usage is dual: when used in place of rest/spread property name it represents abstraction over the object signature when it is used a standalone type it represents a subtype of the string (or number respectively).\r\n\r\n\r\n```TypeScript\r\ndeclare class Object {\r\n      static keys<p extends string, q extends p>(object{...q: {}}): p[];\r\n}\r\n```\r\n\r\nAnd here is the most sophisticated part:  _Key Dependent Types_\r\n\r\nwe introduce special type construct:   `T for Prop`  (I'd like to use this syntax rather than T[Prop] that confused you) where Prop is the name of the type variable that holds object's signature abstraction. For example  `<Prop extends string, T for Prop>` introduces two formal types into type lexical scope, the `Prop` and the `T` where it is known that for each particular value `p` of `Prop` there will be it's own type `T`. \r\n\r\n> We do not say that somewhere is an object that has properties `Props` and their types are `T` ! We only introduce a functional dependency between two types. Type T is correlated with members of type Props, and that's all!\r\n\r\nIt gives us possibility to write such things as\r\n\r\n```TypeScript\r\nfunction unwrap<P extends string, T for P>(obj:{...P: Maybe<T>}): Maybe<{...P: T}> {\r\n  ...\r\n}\r\n\r\nunwrap({a:{value:1}, b:{value:\"A\"}, c:{value: true}}) === { a: 1, b: \"A\", c: true }\r\n// here actual parameters will be inferred as \r\nunwrap<\"a\"|\"b\"|\"c\", {a: number, b: string, c: boolean}>\r\n```\r\nhowever the second parameter is treated not as an object but rather as the abstract map of identifiers to types. In this perspective `T for P` can be used to represent abstract sequences of types for tuples when P is subtype of number (@JsonFreeman ?) \r\n\r\nWhen `T` is used somewhere inside `{...P: ....   T  .... }` it represents exactly one particular type of that map. \r\n\r\nIt is my main idea. \r\nEagerly awaiting any questions, thoughts, criticism -)\r\n\r\n\r\n \r\n\r\n\r\n \r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n"}}