Skip to content

Hex String - Expression produces a union type that is too complex to represent. #43388

Closed

Description

@jrista

Bug Report

I recently ran into this type error. I understand that there are cases where reducing the complexity of a union can be challenging, however in this particular case...I do wonder if it actually is really too complex, given the repetitive nature of the type.

Using the new TS v4 Template Literal types, I have tried to create a type for a MongoDB ObjectId. I started out quite basic:

type Hex =  '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' | 'a' | 'b' | 'c' | 'd' | 'e' | 'f';

export type ObjectId = `${Hex}${Hex}${Hex}${Hex}${Hex}${Hex}${Hex}${Hex}${Hex}${Hex}${Hex}${Hex}${Hex}${Hex}${Hex}${Hex}${Hex}${Hex}${Hex}${Hex}${Hex}${Hex}${Hex}${Hex}`;

This spit back the too complex to represent error. I then wondered if I transitioned some of the complexity from the template literal type to the union, if that might make a difference:

type Hex =
  '00' | '01' | '02' | '03' | '04' | '05' | '06' | '07' | '08' | '09' | '0a' | '0b' | '0c' | '0d' | '0e' | '0f' |
  '10' | '11' | '12' | '13' | '14' | '15' | '16' | '17' | '18' | '19' | '1a' | '1b' | '1c' | '1d' | '1e' | '1f' |
  '20' | '21' | '22' | '23' | '24' | '25' | '26' | '27' | '28' | '29' | '2a' | '2b' | '2c' | '2d' | '2e' | '2f' |
  '30' | '31' | '32' | '33' | '34' | '35' | '36' | '37' | '38' | '39' | '3a' | '3b' | '3c' | '3d' | '3e' | '3f' |
  '40' | '41' | '42' | '43' | '44' | '45' | '46' | '47' | '48' | '49' | '4a' | '4b' | '4c' | '4d' | '4e' | '4f' |
  '50' | '51' | '52' | '53' | '54' | '55' | '56' | '57' | '58' | '59' | '5a' | '5b' | '5c' | '5d' | '5e' | '5f' |
  '60' | '61' | '62' | '63' | '64' | '65' | '66' | '67' | '68' | '69' | '6a' | '6b' | '6c' | '6d' | '6e' | '6f' |
  '70' | '71' | '72' | '73' | '74' | '75' | '76' | '77' | '78' | '79' | '7a' | '7b' | '7c' | '7d' | '7e' | '7f' |
  '80' | '81' | '82' | '83' | '84' | '85' | '86' | '87' | '88' | '89' | '8a' | '8b' | '8c' | '8d' | '8e' | '8f' |
  '90' | '91' | '92' | '93' | '94' | '95' | '96' | '97' | '98' | '99' | '9a' | '9b' | '9c' | '9d' | '9e' | '9f' |
  'a0' | 'a1' | 'a2' | 'a3' | 'a4' | 'a5' | 'a6' | 'a7' | 'a8' | 'a9' | 'aa' | 'ab' | 'ac' | 'ad' | 'ae' | 'af' |
  'b0' | 'b1' | 'b2' | 'b3' | 'b4' | 'b5' | 'b6' | 'b7' | 'b8' | 'b9' | 'ba' | 'bb' | 'bc' | 'bd' | 'be' | 'bf' |
  'c0' | 'c1' | 'c2' | 'c3' | 'c4' | 'c5' | 'c6' | 'c7' | 'c8' | 'c9' | 'ca' | 'cb' | 'cc' | 'cd' | 'ce' | 'cf' |
  'd0' | 'd1' | 'd2' | 'd3' | 'd4' | 'd5' | 'd6' | 'd7' | 'd8' | 'd9' | 'da' | 'db' | 'dc' | 'dd' | 'de' | 'df' |
  'e0' | 'e1' | 'e2' | 'e3' | 'e4' | 'e5' | 'e6' | 'e7' | 'e8' | 'e9' | 'ea' | 'eb' | 'ec' | 'ed' | 'ee' | 'ef' |
  'f0' | 'f1' | 'f2' | 'f3' | 'f4' | 'f5' | 'f6' | 'f7' | 'f8' | 'f9' | 'fa' | 'fb' | 'fc' | 'fd' | 'fe' | 'ff' ;

export type ObjectId = `${Hex}${Hex}${Hex}${Hex}${Hex}${Hex}${Hex}${Hex}${Hex}${Hex}${Hex}${Hex}`;

Sadly, this did not help. While TypeScript did not complain about the Hex union, it still complained about the template literal. The highly repetitive nature of the type makes me think it should be possible to reduce the complexity to something that actually could be represented.

🔎 Search Terms

"Expression produces a union type that is too complex to represent."

🕗 Version & Regression Information

  • This occurs in 4.x

⏯ Playground Link

ObjectId Playground

💻 Code

type Hex =  '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' | 'a' | 'b' | 'c' | 'd' | 'e' | 'f';

export type ObjectId = `${Hex}${Hex}${Hex}${Hex}${Hex}${Hex}${Hex}${Hex}${Hex}${Hex}${Hex}${Hex}${Hex}${Hex}${Hex}${Hex}${Hex}${Hex}${Hex}${Hex}${Hex}${Hex}${Hex}${Hex}`;

🙁 Actual behavior

TypeScript was unable to represent the ObjectId type due to a union that was too complex.

🙂 Expected behavior

TypeScript should be able to handle initially complex unions if the parts of that union are very repetitive... (?)

Activity

  1. jrista commented on Mar 26, 2021

    @jrista
    Author

    Another example, just tried: A 16-digit credit card number:

    type Digit = '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9';
    export type CardNumber = `${Digit}${Digit}${Digit}${Digit}${Digit}${Digit}${Digit}${Digit}${Digit}${Digit}${Digit}${Digit}${Digit}${Digit}${Digit}${Digit}`;

    Interestingly, if I shorten it to this:

    export type CardNumber = `${Digit}${Digit}${Digit}${Digit}`;

    It does not complain.

  2. MartinJohns commented on Mar 26, 2021

    @MartinJohns
    Contributor

    Duplicate of #43283 / #40803 and many others. Another relevant issue that is essentially the same as yours: #43335

    This changed between versions 3.x and 4.x

    Gvien that this feature didn't even exist in TypeScript 3.x, I'm really not sure why you would say this changed between these versions.

  3. jrista commented on Mar 26, 2021

    @jrista
    Author

    I wouldn't say it is a duplicate of the first two. They both use more complex type structures. I still think there is a legitimate question in why it is not possible to reduce such a repetitive type to something that can be properly represented.

  4. MartinJohns commented on Mar 26, 2021

    @MartinJohns
    Contributor

    I still think there is a legitimate question in why it is not possible to reduce such a repetitive type to something that can be properly represented.

    That's probably why the TypeScript team didn't close #43335, which definitely is a duplicate of this. Right now it's not working because the feature was simply never intended for something like this, that's why it builds up on union types which have the hard limit.

  5. typescript-bot commented on Mar 28, 2021

    @typescript-bot
    Contributor

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

  6. locked as resolved and limited conversation to collaborators on Oct 21, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    DuplicateAn existing issue was already created

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions