{"action":"created","issue":{"url":"https://api.github.com/repos/Microsoft/TypeScript/issues/21483","repository_url":"https://api.github.com/repos/Microsoft/TypeScript","labels_url":"https://api.github.com/repos/Microsoft/TypeScript/issues/21483/labels{/name}","comments_url":"https://api.github.com/repos/Microsoft/TypeScript/issues/21483/comments","events_url":"https://api.github.com/repos/Microsoft/TypeScript/issues/21483/events","html_url":"https://github.com/Microsoft/TypeScript/pull/21483","id":292887649,"number":21483,"title":"In switch case, narrow base constraint of type ","user":{"login":"sandersn","id":293473,"avatar_url":"https://avatars1.githubusercontent.com/u/293473?v=4","gravatar_id":"","url":"https://api.github.com/users/sandersn","html_url":"https://github.com/sandersn","followers_url":"https://api.github.com/users/sandersn/followers","following_url":"https://api.github.com/users/sandersn/following{/other_user}","gists_url":"https://api.github.com/users/sandersn/gists{/gist_id}","starred_url":"https://api.github.com/users/sandersn/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/sandersn/subscriptions","organizations_url":"https://api.github.com/users/sandersn/orgs","repos_url":"https://api.github.com/users/sandersn/repos","events_url":"https://api.github.com/users/sandersn/events{/privacy}","received_events_url":"https://api.github.com/users/sandersn/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"assignees":[],"milestone":null,"comments":5,"created_at":"2018-01-30T18:23:10Z","updated_at":"2018-02-21T18:55:21Z","closed_at":null,"author_association":"MEMBER","pull_request":{"url":"https://api.github.com/repos/Microsoft/TypeScript/pulls/21483","html_url":"https://github.com/Microsoft/TypeScript/pull/21483","diff_url":"https://github.com/Microsoft/TypeScript/pull/21483.diff","patch_url":"https://github.com/Microsoft/TypeScript/pull/21483.patch"},"body":"Fixes  #20375\r\n\r\nPreviously, the type itself was narrowed, which was not useful for `T extends 'a' | 'b' | 'c'` and other type parameters that extend literal unions. Note that the previous behaviour was technically correct: at the function declaration, you can't prove that all branches of the case will be used because the type parameter may be instantiated with a smaller union (like `T='a' | 'b'`, in the example above). But the unused cases don't hurt anything, and people expect narrowing to work here.\r\n\r\nFor example:\r\n```ts\r\ndeclare var n: never;\r\nfunction f<T extends 'a' | 'b' | 'c'>(t: T): void {\r\n    switch (t) {\r\n        case 'a': n = t; break; // t should be 'a'\r\n        case 'b': n = t; break; // should be 'b'\r\n        case 'c': n = t; break; // should be 'c'\r\n        default: n = t; break;  // should be never\r\n    }\r\n}\r\n```\r\n\r\nNarrowing is technically incorrect, by analogy with the non-type-parameter example:\r\n\r\n```ts\r\ndeclare var n: never;\r\nfunction f(t: 'a' | 'b'): void {\r\n    switch (t) {\r\n        case 'a': n = t; break;\r\n        case 'b': n = t; break;\r\n        case 'c': n = t; break; // 'c' is unused; 'c' *might* be unused in the type parameter case\r\n        default: n = t; break;\r\n    }\r\n}\r\n```\r\n"},"comment":{"url":"https://api.github.com/repos/Microsoft/TypeScript/issues/comments/367431948","html_url":"https://github.com/Microsoft/TypeScript/pull/21483#issuecomment-367431948","issue_url":"https://api.github.com/repos/Microsoft/TypeScript/issues/21483","id":367431948,"user":{"login":"jack-williams","id":4489219,"avatar_url":"https://avatars1.githubusercontent.com/u/4489219?v=4","gravatar_id":"","url":"https://api.github.com/users/jack-williams","html_url":"https://github.com/jack-williams","followers_url":"https://api.github.com/users/jack-williams/followers","following_url":"https://api.github.com/users/jack-williams/following{/other_user}","gists_url":"https://api.github.com/users/jack-williams/gists{/gist_id}","starred_url":"https://api.github.com/users/jack-williams/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jack-williams/subscriptions","organizations_url":"https://api.github.com/users/jack-williams/orgs","repos_url":"https://api.github.com/users/jack-williams/repos","events_url":"https://api.github.com/users/jack-williams/events{/privacy}","received_events_url":"https://api.github.com/users/jack-williams/received_events","type":"User","site_admin":false},"created_at":"2018-02-21T18:55:21Z","updated_at":"2018-02-21T18:55:21Z","author_association":"CONTRIBUTOR","body":"> However, narrowing-as-assertion doesn't alter or replace the declared type; it just adds to it. Also note (1) the post-if type is still T (2) this is an assertion, not a true narrowing, so the else case isn't never, it's the declared type.\r\n\r\nThis description makes things clearer, thanks. I think what I was doing was (sort-of) in this spirit. I was _technically_ only adding to the type, but the thing I added was the constraint narrowed by the assertion, rather than the assertion directly (so `T extends 3 | true`) would narrow under `typeof x === 'number'`. In the `else` case I think the reason it doesn't narrow to `never` is because the assert facts (not-equal ones) don't apply to unions in constraints like they do directly to unions, as you say. My solution was apply the facts to the constraint (getting `never`) and then adding that to the type to get `T & never`.\r\n\r\n> For your PR, I think switch (typeof x) should use narrowing-as-assertion in the same way as if (typeof x === ...).\r\n\r\nAgreed. I had this behaviour before and will bring it back. I'll change it then ping some of the team so they know when to look at it. There isn't any point reviewing it until I have the right behaviour.\r\n\r\n> As for fixing the narrowing of constrained type parameters, your approach would probably work, but it would be at least a medium-size change — a lot bigger than the one-line change in this PR.\r\n\r\nDefinitely! Again, I wasn't trying to suggest that the PR should be done in style xyz. I just wanted to pick your brains as it was relevant to `switch` + `typeof`."}}
{"actor":{"display_login":"jack-williams"}}