{"action":"created","issue":{"url":"https://api.github.com/repos/angular/angular/issues/5036","labels_url":"https://api.github.com/repos/angular/angular/issues/5036/labels{/name}","comments_url":"https://api.github.com/repos/angular/angular/issues/5036/comments","events_url":"https://api.github.com/repos/angular/angular/issues/5036/events","html_url":"https://github.com/angular/angular/issues/5036","id":114362407,"number":5036,"title":"Use property decorators for all lifecycle hooks instead of interfaces","user":{"login":"IgorMinar","id":216296,"avatar_url":"https://avatars.githubusercontent.com/u/216296?v=3","gravatar_id":"","url":"https://api.github.com/users/IgorMinar","html_url":"https://github.com/IgorMinar","followers_url":"https://api.github.com/users/IgorMinar/followers","following_url":"https://api.github.com/users/IgorMinar/following{/other_user}","gists_url":"https://api.github.com/users/IgorMinar/gists{/gist_id}","starred_url":"https://api.github.com/users/IgorMinar/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/IgorMinar/subscriptions","organizations_url":"https://api.github.com/users/IgorMinar/orgs","repos_url":"https://api.github.com/users/IgorMinar/repos","events_url":"https://api.github.com/users/IgorMinar/events{/privacy}","received_events_url":"https://api.github.com/users/IgorMinar/received_events","type":"User","site_admin":false},"labels":[{"url":"https://api.github.com/repos/angular/angular/labels/comp:%20core","name":"comp: core","color":"c7def8"},{"url":"https://api.github.com/repos/angular/angular/labels/effort2:%20medium%20(day)","name":"effort2: medium (day)","color":"bfe5bf"},{"url":"https://api.github.com/repos/angular/angular/labels/hotlist:%20breaking","name":"hotlist: breaking","color":"d4c5f9"},{"url":"https://api.github.com/repos/angular/angular/labels/type:%20feature","name":"type: feature","color":"EEEEEE"}],"state":"open","locked":false,"assignee":{"login":"jeffbcross","id":463703,"avatar_url":"https://avatars.githubusercontent.com/u/463703?v=3","gravatar_id":"","url":"https://api.github.com/users/jeffbcross","html_url":"https://github.com/jeffbcross","followers_url":"https://api.github.com/users/jeffbcross/followers","following_url":"https://api.github.com/users/jeffbcross/following{/other_user}","gists_url":"https://api.github.com/users/jeffbcross/gists{/gist_id}","starred_url":"https://api.github.com/users/jeffbcross/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jeffbcross/subscriptions","organizations_url":"https://api.github.com/users/jeffbcross/orgs","repos_url":"https://api.github.com/users/jeffbcross/repos","events_url":"https://api.github.com/users/jeffbcross/events{/privacy}","received_events_url":"https://api.github.com/users/jeffbcross/received_events","type":"User","site_admin":false},"milestone":{"url":"https://api.github.com/repos/angular/angular/milestones/49","html_url":"https://github.com/angular/angular/milestones/beta-00","labels_url":"https://api.github.com/repos/angular/angular/milestones/49/labels","id":1339148,"number":49,"title":"beta-00","description":"Issue which must close before we declare beta.","creator":{"login":"naomiblack","id":2286589,"avatar_url":"https://avatars.githubusercontent.com/u/2286589?v=3","gravatar_id":"","url":"https://api.github.com/users/naomiblack","html_url":"https://github.com/naomiblack","followers_url":"https://api.github.com/users/naomiblack/followers","following_url":"https://api.github.com/users/naomiblack/following{/other_user}","gists_url":"https://api.github.com/users/naomiblack/gists{/gist_id}","starred_url":"https://api.github.com/users/naomiblack/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/naomiblack/subscriptions","organizations_url":"https://api.github.com/users/naomiblack/orgs","repos_url":"https://api.github.com/users/naomiblack/repos","events_url":"https://api.github.com/users/naomiblack/events{/privacy}","received_events_url":"https://api.github.com/users/naomiblack/received_events","type":"User","site_admin":false},"open_issues":74,"closed_issues":44,"state":"open","created_at":"2015-10-05T21:32:20Z","updated_at":"2015-11-04T20:22:28Z","due_on":null,"closed_at":null},"comments":38,"created_at":"2015-10-30T21:53:33Z","updated_at":"2015-11-05T03:28:13Z","closed_at":null,"body":"Currently Component and routable component lifecycles are defined via interfaces (e.g. `OnInit`).\r\n\r\nThis is problematic because the interfaces have no runtime representation in JavaScript. So at runtime, we just check if the method defined in the interface (e.g. `onInit`) exists on the component instance and if it does we call it. If a component has a method `onInit` that is not meant to be a lifecycle hook, we'll still call it.\r\n\r\nThese name collisions can result in surprising results, and if we add new lifecycle hooks, we can end up breaking existing components.\r\n\r\nFor these reasons, I propose that we move away from interfaces and use property decorators instead.\r\n\r\nBefore:\r\n```\r\nimport {Component, OnInit} from 'angular2/angular2';\r\n\r\n@Component({\r\n  selector: 'test-foo'\r\n})\r\nclass TestFoo implements OnInit {\r\n  onInit() { ... }\r\n}\r\n```\r\n\r\nAfter:\r\n```\r\nimport {Component, OnInit} from 'angular2/angular2';\r\n\r\n@Component({\r\n  selector: 'test-foo'\r\n})\r\nclass TestFoo {\r\n  @OnInit() onInit() { ... }\r\n}\r\n```\r\n\r\nDart notes: this api can be implemented via transformers for production and via mirrors for development mode.\r\n\r\nMigration notes: I'm not sure how to deal with migration just yet because we are going to reuse the same symbol for different purpose. there might be no good way to provide a transitional path, which would argue for making this change asap.\r\n\r\n//cc: @mhevery @vsavkin @tbosch @btford "},"comment":{"url":"https://api.github.com/repos/angular/angular/issues/comments/153943838","html_url":"https://github.com/angular/angular/issues/5036#issuecomment-153943838","issue_url":"https://api.github.com/repos/angular/angular/issues/5036","id":153943838,"user":{"login":"IgorMinar","id":216296,"avatar_url":"https://avatars.githubusercontent.com/u/216296?v=3","gravatar_id":"","url":"https://api.github.com/users/IgorMinar","html_url":"https://github.com/IgorMinar","followers_url":"https://api.github.com/users/IgorMinar/followers","following_url":"https://api.github.com/users/IgorMinar/following{/other_user}","gists_url":"https://api.github.com/users/IgorMinar/gists{/gist_id}","starred_url":"https://api.github.com/users/IgorMinar/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/IgorMinar/subscriptions","organizations_url":"https://api.github.com/users/IgorMinar/orgs","repos_url":"https://api.github.com/users/IgorMinar/repos","events_url":"https://api.github.com/users/IgorMinar/events{/privacy}","received_events_url":"https://api.github.com/users/IgorMinar/received_events","type":"User","site_admin":false},"created_at":"2015-11-05T03:28:12Z","updated_at":"2015-11-05T03:28:12Z","body":"@mhevery interfaces don't work for JS/TS because they are not retained at runtime.\r\n\r\nWe currently just check if a well now method name is present on a class prototype and we call it, but that's error prone and can result in major headaches when we introduce more lifecycle hooks or when ionic and similar solutions on top of Angular introduce custom hooks (we already need custom hooks for the router and I expect that there will be more).\r\n\r\nwe control the ES5 DSL so we can say that  some properties are special (we already do this for `constructor` property). So for example we can say that `Class` dsl properties starting with `$` will be turned into lifecycle hooks:\r\n\r\n```\r\nvar MyComponent = Component({...}).Class({\r\n  constructor: function() {...},\r\n  $onInit: function() {}. /// everything prefix with $ will be turned into `[ng.onInit]` under the hood.\r\n})\r\n```"}}