Utilize the key types of an object to validate the type of a specified value within the object

I am currently working with an object that contains keys as strings and values as strings. Here is an example of how it looks:

const colors = {
  red: '#ff0000',
  green: '#00ff00',
  blue: '#0000ff',
}

Next, I define a type that only accepts the keys of this object. For instance:

// Output: 'red' | 'green' | 'blue'
type ColorType = keyof typeof colors

Now, my goal is to utilize this type to validate a value from a function that retrieves a value from the colors object. However, I encounter an error when attempting to do so. Here is an example:

const getColor = (color: ColorType): ColorType => {
  // This error occurs: Type 'string' is not assignable to type '"red" | "green" | "blue"'
  return colors[color]
}

How can I overcome this issue?

Answer №1

In case you're intrigued by the concept of ensuring HEX type safety, consider approaching it like this:

type HexNumber = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
type HexString = 'A' | 'B' | 'C' | 'D' | 'E' | 'F' | 'a' | 'b' | 'c' | 'd' | 'e' | 'f'
type StringNumber<T extends number> = `${T}`;
type HEX = HexNumber | StringNumber<HexNumber> | HexString;

type ToArray<T extends string, Cache extends readonly string[] = []> =
    T extends `${infer A}${infer Rest}`
    ? A extends HEX
    ? ToArray<Rest, [...Cache, A]> : A extends ''
    ? 1 : 2 : T extends '' ? Cache extends { length: 6 }
    ? Cache : 'String should have 6 chars. No more, no less' : never;

type Elem = string;

type ReduceToString<
    Arr extends ReadonlyArray<Elem>,
    Result extends string = ''
    > = Arr extends []
    ? Result
    : Arr extends [infer H]
    ? H extends Elem
    ? `${Result}${H}`
    : never
    : Arr extends readonly [infer H, ...infer Tail]
    ? Tail extends ReadonlyArray<Elem>
    ? H extends Elem
    ? ReduceToString<Tail, `${Result}${H}`>
    : never
    : never
    : never;


const colors = {
    red: '#ff0000',
    green: '#00ff00',
    blue: '#0000ff',
} as const

type Colors = typeof colors;

type Tail<T extends string> = T extends `#${infer HEX}` ? HEX : never;

type ColorType = keyof typeof colors

type HexValidation<T extends keyof Colors> = ReduceToString<ToArray<Tail<Colors[T]>>>

function getColor<C extends keyof Colors>(color: C): HexValidation<C>
function getColor<C extends keyof Colors>(color: C) {
    return colors[color]
}

const result = getColor('red') // "ff0000"

Playground

If an invalid HEX property is provided in the colors object, TypeScript will throw an error.

Further explanation can be found on my blog and within this answer

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

Ways to update the value within an object in an array stored in a BehaviorSubject?

My initial data is: const menuItems = [{id: 1, active: false}, {id: 2, active: false}] public menuSubject$ = new BehaviorSubject<MenuItem[]>(menuItems); public menu$ = this.menuSubject$.asObservable(); I am attempting to update the element with ...

Attempting to convert numerical data into a time format extracted from a database

Struggling with formatting time formats received from a database? Looking to convert two types of data from the database into a visually appealing format on your page? For example, database value 400 should be displayed as 04:00 and 1830 as 18:30. Here&apo ...

What are the best practices for integrating Qt with React in TSX?

While I've figured out how to communicate qt with JS successfully, the challenge arises when trying to use React in TSX for frontend development. The previous solution failed on this front. Backend code: #./main.py import os from PySide6.QtWidgets ...

Using setTimeout() and clearTimeout() alongside Promises in TypeScript with strict mode and all annotations included

Many examples of timer implementations using Promises in JavaScript seem overly complex to me. I believe a simpler approach could be taken. However, I am looking for a solution specifically tailored for TypeScript with the "strict": true setting and all ne ...

Warning message in ReactJS Material UI Typescript when using withStyles

I am facing an issue even though I have applied styling as per my requirements: Warning: Failed prop type validation- Invalid prop classes with type function passed to WithStyles(App), expected type object. This warning is originating from Wi ...

Having trouble linking tables to Node.js with TypeScriptyntax?

I am facing an issue with mapping multiple entities using sequelize. I keep encountering the error message " Error: Profesor.hasOne called with something that's not a subclass of Sequelize.Model". How can I resolve this issue? Below is the code for t ...

Creating a dynamic type class in TypeScript that can inherit characteristics from another class

Can a wrapper class be designed to dynamically inherit the properties of another class or interface? For instance... interface Person { readonly firstName: string; readonly lastName: string; readonly birthday?: Date } class Wrapper<T> { ...

Changing a password on Firebase using Angular 5

I am in the process of developing a settings feature for user accounts on an application I've been working on. One key functionality I want to include is the ability for users to update their password directly from the account settings page. To enable ...

angular2 ngif does not effectively conceal HTML elements when set to false

In the HTML file, I have the following code: <p *ngIf="!checklistsready"> not ready </p> <p *ngIf="checklistsready"> Ready </p> And in my TypeScript file, it looks like this: checklistsready: boolean = false; constructor( ...

I'm trying to determine in Stencil JS if a button has been clicked in a separate component within a different class. Can anyone assist

I've created a component named button.tsx, which contains a function that performs specific tasks when the button is clicked. The function this.saveSearch triggers the saveSearch() function. button.tsx {((this.test1) || this.selectedExistingId) && ...

Tips on invoking Bootstrap's collapse function without using JQuery

We are facing a challenge with our TypeScript files as we have no access to jQuery from them. Our goal is to trigger Bootstrap's collapse method... $(object).collapse(method) but without relying on jQuery. Intended Outcome //Replicates the functio ...

Adjusting the background color of the custom input range thumb when the input is disabled

I've customized the input thumb on my range slider, and I'm looking to change its color when it's disabled. I attempted adding a class to the thumb like this: input[type=range]::-webkit-slider-thumb.disabled and also tried adding the disa ...

Vue 3 Electron subcomponents and routes not displayed

Working on a project in Vue3 (v3.2.25) and Electron (v16.0.7), I have integrated vue-router4 to handle navigation within the application. During development, everything works perfectly as expected. However, when the application is built for production, the ...

Using CKEditor5 to Capture and Edit Key Presses

I'm currently working on capturing input from a CKEditor5 within an Angular application using TypeScript. While I am able to successfully display the CKEditor and confirm its presence through logging, I am facing difficulties in capturing the actual i ...

Tips for retrieving both the ID and NAME values from Ionic's Dynamic Select Options

In my Ionic 3 project, I have successfully implemented a dynamic select option. However, I am facing an issue where I can only retrieve either the ID or the Name value of the selected option from the server, but not both. I have tried using JSON.parse and ...

HTML not updating after a change in properties

My template is structured as a table where I update a column based on a button click that changes the props. Even though the props are updated, I do not see the template re-rendered. However, since I am also caching values for other rows in translatedMessa ...

methods for array filtering in typescript

How do I filter an array in TypeScript? I attempted the following findAllPersonsNotVisited():Observable<Person[]> { var rightNow = new Date(); var res = rightNow.toISOString().slice(0,10).replace(/-/g,"-"); return this.db.list(& ...

Extracting the "defined" type from a TypeScript property during runtime

My current task Presently, I am iterating through the keys of an object and transferring their values to another object. interface From { [key: string]: string; } let from: From = { prop1: "foo", prop2: "23", }; interface To { [key: str ...

`How to utilize the spread operator in Angular 4 to push an object to a specific length`

One issue I'm facing is trying to push an object onto a specific index position in an array, but it's getting pushed to the end of the array instead. this.tradingPartner = new TradingPartnerModel(); this.tradingPartners = [...this.tradingPartner ...

The error at core.js:4002 is a NullInjectorError with a StaticInjectorError in AppModule when trying to inject FilterService into Table

While exploring PrimeNg Table control in my application - as a beginner in PrimeNg & Angular, I encountered an error No provider for FilterService! shown below: core.js:4002 ERROR Error: Uncaught (in promise): NullInjectorError: StaticInjectorError(AppMo ...