'How can I define a type for a css color in TypeScript?

I have the following example code snippet:

type Color = string;

interface Props {
    color: Color;
    text: string;
}

function Badge(props: Props) {
    return `<div style="color:${props.color}">${props.text}</div>`;
}

var badge = Badge({
    color: '#F00',
    text: 'Danger'
});

console.log(badge);

Playground

I'm trying to get a build error if the color is invalid, like so:

var badge = Badge({
    color: 'rgba(100, 100, 100)',
    text: 'Danger'
});

Is there a way to define Color so that it allows only strings matching one of the following patterns?

  • #FFF
  • #FFFFFF
  • rgb(5, 5, 5)
  • rgba(5, 5, 5, 1)
  • hsa(5, 5, 5)

I realize that there are colors like red and white but that might make this harder to answer if Color can accept those.



Solution 1:[1]

There was a proposal for a type of string which matches a pattern (regex or something else), but that proposal haven't come to fruition yet.

As a result, what you ask for is unfortunately impossible as of TypeScript 2.2.

Solution 2:[2]

type RGB = `rgb(${number}, ${number}, ${number})`;
type RGBA = `rgba(${number}, ${number}, ${number}, ${number})`;
type HEX = `#${string}`;

type Color = RGB | RGBA | HEX;

`${...}` notation is available on new (^4.1) ts versions.

https://www.typescriptlang.org/docs/handbook/2/template-literal-types.html

Solution 3:[3]

You can't do this yet in a general sense, but you can use constants and string literal types if you have a well defined set of colors:

type Color = "#FFFFFF" | "#FF0000" | "#0000FF";
const WHITE: Color = "#FFFFFF";
const RED: Color = "#FF0000";
const BLUE: Color = "#0000FF";

Obviously, this won't be practical if you want to allow any color, but in reality you probably do want to have re-usable color variables anyway.

In my project I use a script to generate a similar file from my colors.css file which defines a bunch of CSS properties:

:root {
  --primary-red: #ff0000;
  --secondary-red: #993333;
  /* etc */
}

Which gets converted to:

export const primaryRed: Color = "#ff0000";
export const secondaryRed: Color = "#993333";
// etc
export type Color = "#ff0000" | "#993333" // | etc...

And I'd use it like:

import {primaryRed} from "./Colors.ts";

interface BadgeProps {
    color: Color;
    text: string;
}  

var badge = Badge({
    color: primaryRed,
    text: 'Danger'
});

Solution 4:[4]

It is theoretically possible with union types, however if you JUST do hex codes, you have well over 16,000,000 possible combinations, and typescript (4.6.3 at least) does not like that idea.

It has been on the backburner for MS for over a year now https://github.com/microsoft/TypeScript/issues/42790

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Oliver Salzburg
Solution 2 styfle
Solution 3
Solution 4 d3rpp