IssueRaiser

Relate control flow to conditional types in return types

## Search Terms control flow conditional return type cannot assign extends ## Suggestion Developers are eager to use conditional types in functions, but this is unergonomic: ```ts type Person = { name: string; address: string; }; type Website = { name: string; url: URL }; declare function isWebsite(w: any): w is Website; declare function isPerson(p: any): p is Person; function getAddress<T extends Person | Website>(obj: T): T extends Person ? string : URL { if (isWebsite(obj)) { // Error return obj.url; } else if (isPerson(obj)) { // Another error return obj.address; } throw new Error('oops'); } ``` The errors here originate in the basic logic: > `obj.url` is a `URL`, and a `URL` isn't a `T extends Person ? string : URL` By some mechanism, this function should *not* have an error. ## Dead Ends The current logic is that all function return expressions must be assignable to the explicit return type annotation (if one exists), otherwise an error occurs. A tempting idea is to change the logic to "Collect the return type (using control flow to generate conditional types) and compare that to the annotated return type". This would be a bad idea because the function implementation would effectively reappear in the return type: ```ts function isValidPassword<T extends string>(s: T) { if (s === "very_magic") { return true; } return false; } // Generated .d.ts function isValidPassword<T extends string>(s: T): T extends "very_magic" ? true :

Posted by RyanCavanaugh on Oct 9, 2019, 8:41 PM

Tags

Related issues

Raise real-world problems, find people facing the same issue, and discuss solutions.3,500 issues0 comments

github (Other)

Relate control flow to conditional types in return types

RyanCavanaughOct 9, 2019, 8:41 PM

## Search Terms control flow conditional return type cannot assign extends ## Suggestion Developers are eager to use conditional types in functions, but this is unergonomic: ```ts type Person = { name: string; address: string; }; type Website = { name: string; url: URL }; declare function isWebsite(w: any): w is Website; declare function isPerson(p: any): p is Person; function getAddress<T extends Person | Website>(obj: T): T extends Person ? string : URL { if (isWebsite(obj)) { // Error return obj.url; } else if (isPerson(obj)) { // Another error return obj.address; } throw new Error('oops'); } ``` The errors here originate in the basic logic: > `obj.url` is a `URL`, and a `URL` isn't a `T extends Person ? string : URL` By some mechanism, this function should *not* have an error. ## Dead Ends The current logic is that all function return expressions must be assignable to the explicit return type annotation (if one exists), otherwise an error occurs. A tempting idea is to change the logic to "Collect the return type (using control flow to generate conditional types) and compare that to the annotated return type". This would be a bad idea because the function implementation would effectively reappear in the return type: ```ts function isValidPassword<T extends string>(s: T) { if (s === "very_magic") { return true; } return false; } // Generated .d.ts function isValidPassword<T extends string>(s: T): T extends "very_magic" ? true :

Comments (0)

No comments yet. Start the discussion.

Comment on this issue