Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Discriminate string or number literal from general type. #55095

Closed
4 of 5 tasks
ccorcos opened this issue Jul 20, 2023 · 3 comments
Closed
4 of 5 tasks

Discriminate string or number literal from general type. #55095

ccorcos opened this issue Jul 20, 2023 · 3 comments
Labels
Duplicate An existing issue was already created

Comments

@ccorcos
Copy link

ccorcos commented Jul 20, 2023

Suggestion

πŸ” Search Terms

  • exclude string literal from string type
  • exclude number literal from number type
  • discriminate string literal

βœ… Viability Checklist

My suggestion meets these guidelines:

  • This wouldn't be a breaking change in existing TypeScript/JavaScript code
  • This wouldn't change the runtime behavior of existing JavaScript code
  • This could be implemented without emitting different JS based on the types of the expressions
  • This isn't a runtime feature (e.g. library functionality, non-ECMAScript syntax with JavaScript output, new syntax sugar for JS, etc.)
  • This feature would agree with the rest of TypeScript's Design Goals.

⭐ Suggestion

πŸ“ƒ Motivating Example

I want to be able to write code such as

type ApiResponse<Body> = {status: 200, body: Body} | {status: number, body: unknown}

// Get this type from calling an API...
declare const response: ApiResponse<{text: string}>

if (response.status === 200) {
  response.body.text // this is a string
} else {
  response.body // this is unknown 
}

Fundamentally, this seems like the type checker needs to evaluate literal types before more general types.

I've also tried using Exclude but that doesnt help for obvious reasons.

type ApiResponse<Body> = {status: 200, body: Body} | {status: Exclude<number, 200>, body: unknown}

This is also useful for strings and string literals too, e.g. {type: "a", a: number} | {type: string, value: unknown}

πŸ’» Use Cases

I think its surprisingly common that there are well known types we can use to narrow down a value, while there is still a large unknown amount of types that we aren't aware of an perhaps don't even care about.

The variety of http responses I could get is much larger than I can properly type (unfortunately), but the same can be said for progressively typing a large library. Perhaps I only care about a few different object types, but I still want there to be a catch all for the things I haven't typed yet and might run into...

@RyanCavanaugh
Copy link
Member

RyanCavanaugh commented Jul 20, 2023

You'd need negated types for this to work properly, since this is a legal (but unsound) construction if this were allowed:

const n: number = 200;
const m = { status: n, body: 42 };
const response: ApiResponse<{text: string}> = m;
if (response.status === 200) {
  response.body.text // claimed as string, but is undefined

@RyanCavanaugh RyanCavanaugh added the Duplicate An existing issue was already created label Jul 20, 2023
@ccorcos
Copy link
Author

ccorcos commented Jul 21, 2023

Ah yeah, i guess that's basically what I was getting at with Exclude...

#4196

Seems really useful, but probably a pretty big amount of work to implement.

Thanks for the help!

@typescript-bot
Copy link
Collaborator

This issue has been marked as "Duplicate" and has seen no recent activity. It has been automatically closed for house-keeping purposes.

@typescript-bot typescript-bot closed this as not planned Won't fix, can't repro, duplicate, stale Jul 24, 2023
This issue was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Duplicate An existing issue was already created
Projects
None yet
Development

No branches or pull requests

3 participants