1

Such as:

let str: ByteString = "01afe3"; // valid
let str1: ByteString = "0a1" // invalid, hex string length should be even
let str2: ByteString = "hello" //invalid, only hex allow

The value can be any string that is a valid hex.

I have tried the code below:

type HexChar = '0' | '1' | '2' | '3' | '4' | '5' | '6'| '7' | '8' | '9' | 'A' | 'B' | 'C' | 'D' | 'E' | 'F';
type HexColor = `#${HexChar}${HexChar}${HexChar}${HexChar}${HexChar}${HexChar}`;
let color: HexColor = '#123456';

But this only works when the value is fixed length.

We want a type that can handle any length, if the string value is valid.

NoCommandLine
  • 5,044
  • 2
  • 4
  • 15
qtom zheng
  • 66
  • 2
  • 2
    https://www.typescriptlang.org/docs/handbook/advanced-types.html Have you ever read this page? – DreamBold Dec 12 '22 at 07:37
  • 1
    Please check [this](https://stackoverflow.com/questions/66851513/a-way-to-mark-arbitrary-strings-in-typescript-template-literals#answer-66852494) answer and [my article](https://catchts.com/hex-validation). Please dont forget that apart from allowed values, you also need to check the length – captain-yossarian from Ukraine Dec 12 '22 at 10:35
  • 1
    If a helper function doesn't meet your needs, then you should [edit] the question to clarify that instead of writing it in an answer to the question (where nobody will be looking when trying to come up with their own answer). – jcalz Dec 12 '22 at 17:09
  • If you do edit the question to add that constraint, then the answer is that there is no such type that works the way you want. I would be happy to write up an answer explaining, with links to sources. Would that fully address the question or am I missing something? (Please mention @jcalz if you reply so that I'm notified) – jcalz Dec 12 '22 at 17:12

2 Answers2

1

First you need to define a generic HexType which is a conditional type and uses recursive logic:

type HexChar = '0' | '1' | '2' | '3' | '4' 
  | '5' | '6'| '7' | '8' | '9' | 'A' | 'B' | 'C' | 'D' | 'E' | 'F'
  | 'a' | 'b' | 'c' | 'd' | 'e' | 'f';

type HexType<T extends string> = T extends `${infer R1}${infer R2}`
  ? R1 extends HexChar
    ? `${R1}${HexType<R2>}`
    : never
  : `${T}`;

Then create a helper function which gets any value but if the value type is not HexType the argument type will be never so the function gives you an error.

const MyHexTypeFunction = <T extends string>(value: HexType<T>) => value;

For example :

const value = MyHexTypeFunction("qxb12");   //gives never type and also gives error

const value2 = MyHexTypeFunction("AB234"); //value2 type is "AB234"

If you want the Hex string to be even length you can use another generic type and helper function like so:

type HasEvenLegth<T extends string> =
  T extends `${infer R1}${infer R2}${infer R3}`
    ? R3 extends ""
      ? T
      : `${R1}${R2}${HasEvenLegth<R3>}`
    : T extends ""
    ? ""
    : never;

const HasEvenLegthFunction = <T extends string>(value: HasEvenLegth<T>) => value;

For example :

const value3 = HasEvenLegthFunction(MyHexTypeFunction("E23a318")); 
//gives never type and also gives error because it has odd length

const value4 = HasEvenLegthFunction(MyHexTypeFunction("EQ")); 
//gives never type and also gives error because it has invalid character

const value5 = HasEvenLegthFunction(MyHexTypeFunction("AbbbB234")); 
//value5 type is "AbbbB234" it has no error

You can read more about the conditional types here.

mahooresorkh
  • 1,361
  • 2
  • 8
  • 16
0

Thank you.

All solution I found is below:

type HexChar = '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' | 'a' | 'b' | 'c' | 'd' | 'e' | 'f' | 'A' | 'B' | 'C' | 'D' | 'E' | 'F';


type HexType<T extends string> = 
  T extends `${infer R1}${infer R2}${infer R3}`
  ?  R1 extends HexChar
    ? R2 extends HexChar
      ? `${R1}${R2}${HexType<R3>}`
      : never
    : never
  : T extends `${infer R1}${infer R2}`
    ? R1 extends `${HexChar}${HexChar}`
      ? `${R1}${HexType<R2>}`
      : never
  : `${T}`;

/**
 * Converts a hex literal to string.
 * @param {string} hexStr - should be in format of hex literal, i.e. `/^([0-9a-fA-F]{2})*$/`
 */
export function hexToString<T extends string >(hexStr: HexType<T>): string {

  return hexStr;
};


hexToString("00aa")

But this requires a helper function hexToString. I don't want a helper function, I just want a type.

NoCommandLine
  • 5,044
  • 2
  • 4
  • 15
qtom zheng
  • 66
  • 2
  • This answer is very similar to the existing answer; why is this preferable to the other one? – jcalz Dec 12 '22 at 17:08
  • 1
    If a helper function doesn't meet your needs, then you should put that information in the *question itself* and not here in an answer. – jcalz Dec 12 '22 at 17:12