{"action":"created","issue":{"url":"https://api.github.com/repos/Microsoft/TypeScript/issues/15680","repository_url":"https://api.github.com/repos/Microsoft/TypeScript","labels_url":"https://api.github.com/repos/Microsoft/TypeScript/issues/15680/labels{/name}","comments_url":"https://api.github.com/repos/Microsoft/TypeScript/issues/15680/comments","events_url":"https://api.github.com/repos/Microsoft/TypeScript/issues/15680/events","html_url":"https://github.com/Microsoft/TypeScript/issues/15680","id":227170857,"number":15680,"title":"Smarter type inference for functional programming (RxJS, Rambda, etc)","user":{"login":"benlesh","id":1540597,"avatar_url":"https://avatars3.githubusercontent.com/u/1540597?v=3","gravatar_id":"","url":"https://api.github.com/users/benlesh","html_url":"https://github.com/benlesh","followers_url":"https://api.github.com/users/benlesh/followers","following_url":"https://api.github.com/users/benlesh/following{/other_user}","gists_url":"https://api.github.com/users/benlesh/gists{/gist_id}","starred_url":"https://api.github.com/users/benlesh/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/benlesh/subscriptions","organizations_url":"https://api.github.com/users/benlesh/orgs","repos_url":"https://api.github.com/users/benlesh/repos","events_url":"https://api.github.com/users/benlesh/events{/privacy}","received_events_url":"https://api.github.com/users/benlesh/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"assignees":[],"milestone":null,"comments":0,"created_at":"2017-05-08T20:52:29Z","updated_at":"2017-05-08T23:02:08Z","closed_at":null,"body":"<!-- BUGS: Please use this template. -->\r\n<!-- QUESTIONS: This is not a general support forum! Ask Qs at http://stackoverflow.com/questions/tagged/typescript -->\r\n<!-- SUGGESTIONS: See https://github.com/Microsoft/TypeScript-wiki/blob/master/Writing-Good-Design-Proposals.md -->\r\n\r\n**TypeScript Version:**  2.2.1 / nightly (2.2.0-dev.201xxxxx)\r\n\r\nTypeScript is unable to infer types through higher-order functions.\r\n\r\n**Code**\r\n\r\nGiven some imaginary class `SetOf`, which is just some set of values we want to compose operations over... We'll try the following:\r\n\r\n```ts\r\n// This is a contrived class. We could do the same thing with Observables, etc.\r\nclass SetOf<A> {\r\n  private _store: A[];\r\n\r\n  add(a: A) {\r\n    this._store.push(a);\r\n  }\r\n\r\n  transform<B>(transformer: (a: SetOf<A>) => SetOf<B>): SetOf<B> {\r\n    return transformer(this);\r\n  }\r\n\r\n  forEach(fn: (a: A, index: number) => void) {\r\n      this._store.forEach((a, i) => fn(a, i));\r\n  }\r\n}\r\n\r\nfunction compose<A, B, C>(fnA: (a: SetOf<A>) => SetOf<B>, fnB: (b: SetOf<B>) => SetOf<C>): (x: SetOf<A>) => SetOf<C>;\r\nfunction compose<A, B, C, D>(fnA: (a: SetOf<A>) => SetOf<B>, fnB: (b: SetOf<B>) => SetOf<C>, fnC: (c: SetOf<C>) => SetOf<D>):(x: SetOf<A>) => SetOf<C>;\r\n\r\n/* ... etc ... */\r\nfunction compose<T>(...fns: ((x: T) => T)[]): (x: T) => T {\r\n  return (x: T) => fns.reduce((prev, fn) => fn(prev), x);\r\n}\r\n\r\nfunction map<A, B>(fn: (a: A) => B) {\r\n  return (a: SetOf<A>) => {\r\n    const b = new SetOf<B>();\r\n    a.forEach(x => b.add(fn(x)));\r\n    return b;\r\n  }\r\n}\r\n\r\nfunction filter<A>(predicate: (a: A) => boolean) {\r\n  return (a: SetOf<A>) => {\r\n    const result = new SetOf<A>();\r\n    a.forEach(x => {\r\n      if (predicate(x)) result.add(x);\r\n    });\r\n   return result;\r\n  }\r\n}\r\n\r\nconst testSet = new SetOf<number>();\r\ntestSet.add(1);\r\ntestSet.add(2);\r\ntestSet.add(3);\r\n\r\n// THE PROBLEM IS HERE\r\n// all functions below are unable to infer any types.\r\n// The user will be required to annotate the types manually at each step.\r\ntestSet.transform(\r\n  compose(\r\n    filter(x => x % 1 === 0),\r\n    map(x => x + x),\r\n    map(x => x + '!!!'),\r\n    map(x => x.toUpperCase())\r\n  )\r\n)\r\n```\r\n\r\n## Libraries Where This Problem Will Exist\r\n\r\n### RxJS\r\n\r\nWe want to move RxJS over to using \"lettable operators\". That means operators that are built in a similar fashion to what you see in the example able. The current prototype augmentation is untenable for large applications, and makes tree-shaking hard if not impossible with regards to Rx.\r\n\r\n### Rambda\r\n\r\nA widely popular functional programming library will undoubtedly have the same issues. Especially give that (I think) the `compose` function shown above exists (probably in a better form) within Ramdba.\r\n\r\n### Redux\r\n\r\n`combineReducers` in redux is liable to have this same problem, at least when dealing with typed reducers. I don't think the reducer's types can be inferred inside of that call. However, I'm not sure it's a common use case for Redux to have inline reducers in a `combineReducers` call.\r\n\r\n### Plain JavaScript\r\n\r\nThis problem would exist for any higher-order function used in this manner within JavaScript:\r\n\r\n```ts\r\n// given the same `compose` function from above:\r\n\r\nconst result = [1, 2, 3, 4].map(\r\n  compose(\r\n    x => x + x,\r\n    x => x + '!!!',\r\n    x => parseInt(x)\r\n  )\r\n);\r\n\r\nconsole.log(result); // [2, 4, 6, 8]\r\n```\r\n\r\ncc/ @rkirov @igorminar @david-driscoll @alexeagle "},"comment":{"url":"https://api.github.com/repos/Microsoft/TypeScript/issues/comments/300014762","html_url":"https://github.com/Microsoft/TypeScript/issues/15680#issuecomment-300014762","issue_url":"https://api.github.com/repos/Microsoft/TypeScript/issues/15680","id":300014762,"user":{"login":"benlesh","id":1540597,"avatar_url":"https://avatars3.githubusercontent.com/u/1540597?v=3","gravatar_id":"","url":"https://api.github.com/users/benlesh","html_url":"https://github.com/benlesh","followers_url":"https://api.github.com/users/benlesh/followers","following_url":"https://api.github.com/users/benlesh/following{/other_user}","gists_url":"https://api.github.com/users/benlesh/gists{/gist_id}","starred_url":"https://api.github.com/users/benlesh/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/benlesh/subscriptions","organizations_url":"https://api.github.com/users/benlesh/orgs","repos_url":"https://api.github.com/users/benlesh/repos","events_url":"https://api.github.com/users/benlesh/events{/privacy}","received_events_url":"https://api.github.com/users/benlesh/received_events","type":"User","site_admin":false},"created_at":"2017-05-08T23:02:08Z","updated_at":"2017-05-08T23:02:08Z","body":"FWIW, [this appears to work in FlowType](https://goo.gl/AI45Da)"}}
{"actor":{"display_login":"benlesh"}}