Skip to content

Get discriminated union variant type #41271

@macabeus

Description

@macabeus

Search Terms

discriminated union, variant, mapped types

Suggestion

We can get a property type from object without any surprise:

type Payload = { foo: string }
type Foo = Payload['foo'] // string

But if the object is a discriminated union, we can only get a type of a member that repeats on all variants

type Payload = (
  {
    result: 'success'
    data: number
  } |
  {
    result: 'error'
    errorCode: 'invalid-token' | 'expired-token'
  }
)

type Errors = Payload[ ???? ] // we can't =(

The only way at this moment is extracting the type into a new one:

type PayloadError = 'invalid-token' | 'expired-token'
type Payload = (
  {
    result: 'success'
    data: number
  } |
  {
    result: 'error'
    errorCode: PayloadError
  }
)

type Errors = PayloadError

Use Cases

Extracting a type from a variant has two problems:

  • is inconvenience if we are using an external library
  • if we want this type only on a specific moment that would be better expressed without a new type (same use case of using Payload['foo'] instead of creating a Foo type)

Examples

I really don't know how could be the syntax. Maybe could be something like

type PayloadError = Payload['result'] when 'error'
type Errors = (Payload['result'] when 'error')['errorCode']

Related

The suggestion #39103 is similar, but for a different use case.
I'm suggesting to get the variant type outside of the declaration, and this suggestion want to get the variant type inside of the type + ternary operator in order to write some shortcuts on the declaration type.

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, etc.)
  • This feature would agree with the rest of TypeScript's Design Goals.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions