0

I have an object which consists of keys as strings, and value as strings. It looks like this:

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

I then create a type that accepts only the keys of an object. For example:

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

Then, I want to use this type to check a value from a function that returns a value from colors. But it throws an error. For example:

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

How can I do this?

bravokiloecho
  • 1,413
  • 5
  • 22
  • 39

1 Answers1

1

Btw, if you are interested in HEX type safety, you can try next approach:

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 you try to provide invalid HEX property in colors object, TS will throw an error.

More explanation you can find in my blog and this answer