# Using TypeScript Intersections to Preserve Literal Autocomplete with Arbitrary Strings

DevFeed: [Using TypeScript Intersections to Preserve Literal Autocomplete with Arbitrary Strings](<https://devfeed.tech/articles/typescript-magic-19164.md>)

Original publisher: [Read original article](<https://artsy.github.io/blog/2023/03/01/typescript-magic/>)

Published: 2023-03-01T00:00:00Z

Content type: tutorial

Language: en

Sources: [Artsy](<https://devfeed.tech/sources/artsy.md>)

Topics: [TypeScript](<https://devfeed.tech/topics/typescript.md>), [Design system](<https://devfeed.tech/topics/design-system.md>), [React Native](<https://devfeed.tech/topics/react-native.md>), [CSS](<https://devfeed.tech/topics/css.md>)

Tags: [autocomplete](<https://devfeed.tech/tags/autocomplete.md>), [css](<https://devfeed.tech/tags/css.md>), [design-system](<https://devfeed.tech/tags/design-system.md>), [palette](<https://devfeed.tech/tags/palette.md>), [react-native](<https://devfeed.tech/tags/react-native.md>), [tools](<https://devfeed.tech/tags/tools.md>), [types](<https://devfeed.tech/tags/types.md>), [typescript](<https://devfeed.tech/tags/typescript.md>)

## AI overview

This tutorial explains a TypeScript type pattern that preserves autocomplete and typechecking for predefined design-system color values while still accepting arbitrary strings such as hexadecimal, RGB, HSL, and CSS color names. It uses an intersection-based type trick to keep specific string literals distinct from the general string type.

## Source excerpt

At Artsy, we love TypeScript. We use it in most of our node/web/mobile repos. Today, I want to talk about a specific case we found while trying to make our types more strict on palette-mobile, which is our Design System for React Native. Check this out: const welp: "hello" | "world" | string // `welp` is of type `string`. Like the comment says, even though we have two specific strings, the fact that we do a union with string, makes welp have a type of just string. This is because both "hello" and "world" are strings, and the union tends to go to the type that includes the most. Think of set theory and bubbles. "hello" is a type by itself, and "world" is a type by itself. Unioning them together gives us a new type, which is a bubble that contains both "hello" and "world". In that "hello" | "world" union bubble, we see both "hello" and "world" types as subsets. The string bubble contains all strings, so it contains "hello" and "world" and "hello" | "world", so the union of them with string is string. That is usually ok, but for our case, it didn't work. Here is what we wanted to do. The problem In our Design System, we have certain color, named like black100, black80, blue100, red150 etc. We can have a type like type ColorDSValue = "black100" | "black80" | "blue100" | "red150" // | etc and that works great. We get to have autocomplete, typechecking, all the good stuff that TypeScript brings. But we also want to support any other string, like "#000000", "#000", "rgb(0,0,0)", "rgba(0,0,0,0.5)", "hsl(0,0%,0%)", "hsla(0,0%,0%,0.5)". Ok, you might say, just make more types like type ColorHexValue = `#${string}` type ColorRGBValue = `rgb(${number},${number},${number})` type ColorRGBAValue = `rgba(${number},${number},${number},${number})` type ColorHSLValue = `hsl(${number},${number}%,${number}%)` and so on. That's great. So far, so good. We also want to make sure CSS color names are accepted. So then we add something like type ColorCSSString = "red" | "blue" | "hotpink" //