Creating a TypeScript type that can verify the validity of a hexadecimal string value

For example:

let hexStr: string = "01afe3"; // valid
let hexStr1: string = "0a1" // invalid, hex string length should be even
let hexStr2: string = "hello" //invalid, only hex characters allowed

The string value must be a valid hexadecimal.

I attempted the following code:

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

However, this will only work for fixed-length values.

We need a type that can accommodate any length as long as the string is valid hex.

Answer №1

To start, you must establish a generic HexType that utilizes recursive logic within a conditional type:

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}`;

Next, create a function that only accepts values of type HexType; if the value is not of this type, the argument will be never:

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

For instance:

const value = MyHexTypeFunction("qxb12");   //results in a type of never and throws an error

const value2 = MyHexTypeFunction("AB234"); //value2 has a type of "AB234"

If you require your Hex string to have an even length, you can implement 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")); 
//results in a type of never and throws an error due to odd length

const value4 = HasEvenLegthFunction(MyHexTypeFunction("EQ")); 
//results in a type of never and throws an error due to invalid character

const value5 = HasEvenLegthFunction(MyHexTypeFunction("AbbbB234")); 
//value5 is of type "AbbbB234" with no errors

Further information on conditional types can be found here.

Answer №2

Appreciate the assistance.

Here is the solution I have come up with:

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 convertHexToString<T extends string >(hexStr: HexType<T>): string {

  return hexStr;
};


convertHexToString("00aa")

However, it seems like this approach necessitates the use of a helper function convertHexToString. Ideally, I would prefer to achieve this without relying on a separate function.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Executing TypeScript functions that call multiple times to change the innerHTML of an Angular div

My array consists of objects with dates spanning approximately 2 years, prices (which are added dynamically post API calls), and changeable validations within the Angular app: calendarArrayDates = [ {"date": "2018-10-23", "price":"2313", "date_is_valid" ...

Implementing an interface with a variable key and defining the key simultaneously

I am trying to design an interface with a fixed key, as well as a variable key, like this : interface Data { api?: { isReady: boolean; }; [key: string]: string; } This setup gives me the following error message : Property 'api' of typ ...

Display TypeScript console log exclusively during development mode

Can console logs in TypeScript/JavaScript be selectively outputted based on Webpack bundling mode? I frequently use comments for status messages in my app and do not want to remove them for production versions. ...

The struggle of accessing child components using ViewChild in Angular

I am facing an issue with a dialog box that is supposed to display a child component separately. Below is the code for the child component: @Component({ selector: 'userEdit', templateUrl: './edituser.component.html', styleUrls: [ ...

setting the minimum date for a datepicker

Does anyone know how to set the minimum date for a calendar to be 2 days from the current date? For example, if today is the 27th, the minimum date should be the 29th. Any suggestions? Thanks. https://i.sstatic.net/7yHhH.png #html code <mat-form-field ...

Changing the names of the remaining variables while object destructuring in TypeScript

UPDATE: I have created an issue regarding this topic on github: https://github.com/Microsoft/TypeScript/issues/21265 It appears that the syntax { ...other: xother } is not valid in JavaScript or TypeScript, and should not compile. Initial Query: C ...

Mapping JSON objects to TypeScript Class Objects

I am in the process of transitioning my AngularJS application to Angular 6, and I'm encountering difficulties converting a JSON object into a TypeScript object list. In my Angular 6 application, I utilize this.http.get(Url) to retrieve data from an AP ...

What is the significance of having both nulls in vue's ref<HTMLButtonElement | null>(null)?

Can you explain the significance of these null values in a vue ref? const submitButton = ref<HTMLButtonElement | null>(null); ...

Ways to assign unpredictable values (such as ids, dates, or random numbers) to a Domain Entity or Aggregate Root when it has been injected as dependencies

I am currently developing a frontend repository that follows an innovative hexagonal architecture approach with domain-driven design principles, and it utilizes Redux Toolkit. The development process involves Test-Driven Development (TDD) where I employ c ...

Typescript error: The 'prev' argument does not match the parameter type

Upon implementing this code snippet export const resetErrors = (setErrors: (errors: Array<ErrorInterface>) => void, field: string): void => setErrors((prev: Array<ErrorInterface>): void => prev.filter((el: ErrorInterface) => el.fiel ...

Find a string that matches an element in a list

I currently have a list structured like this let array = [ { url: 'url1'}, { url: 'url2/test', children: [{url: 'url2/test/test'}, {url: 'url2/test2/test'}], { url: 'url3', children: [{url: & ...

Angular is declining to implement the style originating from the specified URL

I'm currently working on an Angular application and attempting to lazy load a module called ProjectsModule. The projects component is displayed without any issues, but when I navigate to a specific project like /projects/1, everything looks fine until ...

How come my push function is not functioning properly on Ionic?

When working with ionic 3, I encountered an issue with the alert controller while trying to push an element into my array. Despite following the necessary steps of receiving parameters and pushing them, I keep encountering a significant error when attempti ...

Reactive form within a parent object for nested counting

I am looking to generate a nested form based on the following data: The current data available is as follows: mainObject = { adminname: 'Saqib', adminemail: '<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="40 ...

In JavaScript, sort the array of objects based on the key name

I have an array of objects like the following: employees = [ {name: "Tony Stark", department: "IT"}, {name: "Peter Parker", department: "Pizza Delivery"}, {name: "Bruce Wayne", department: "IT"}, {name: "Clark Kent", department: "Editin ...

Encountered an issue with importing a JavaScript library in TypeScript

I am trying to import a JavaScript library called Akarata. I have followed the suggestions from the internet, such as: import * as akarata from 'akarata/dist'; or import * as akarata from 'akarata'; However, I am still encountering ...

When onSubmit is triggered, FormData is accessible. But when trying to pass it to the server action, it sometimes ends up as null

I am currently utilizing NextJS version 14 along with Supabase. Within my codebase, I have a reusable component that I frequently utilize: import { useState } from 'react'; interface MyInputProps { label: string; name: string; value: stri ...

The TypeScript compilation is missing Carousel.d.ts file. To resolve this issue, ensure that it is included in your tsconfig either through the 'files' or 'include' property

While trying to build an Angular application for server-side execution, I encountered the following errors: ERROR in ./src/app/shared/components/carousel/interface/Carousel.d.ts Module build failed: Error: /home/training/Desktop/vishnu/TemplateAppv6/src ...

What is the best way to implement a switch case with multiple payload types as parameters?

I am faced with the following scenario: public async handle( handler: WorkflowHandlerOption, payload: <how_to_type_it?>, ): Promise<StepResponseInterface> { switch (handler) { case WorkflowHandlerOption.JOB_APPLICATION_ACT ...

Typescript - Postpone defining generic type until invoking function

Trying to modify an existing API by defining a generic type to determine the key/value pairs that can be passed to the function, and also for IntelliSense purposes. (Working with vue.js in this case, but it's not crucial.) Here is the structure of th ...