• _hello
  • _about-me
  • _projects
  • _blog
  • _support
_contact-me
find me in:
@faeztgh
cd ../blog~/blog/union-types-and-autocomplete-helper
  • TypeScript
  • Union Types
  • Autocomplete
  • Developer Experience

Leveraging Union Types and Union Autocomplete Helper in TypeScript

Keep IDE autocomplete alive when a union type mixes specific string literals with a broad string — and wrap the trick in a reusable UnionAutocompleteHelper type.

FFaez Tgh·Dec 6, 20231 min read·183 words
// share: post linkedin
TypeScript union types with a string autocomplete helper

Union types in TypeScript let a value be one of several types. A common case is a prop that should accept a set of known string literals — like a button size of "xs" | "sm" | "md" | "lg" — while still allowing an arbitrary string for flexibility.

The catch: if we simply add string to the union, we lose the autocomplete on those literal values. Let's look at the pattern that fixes it, and then wrap it in a reusable helper.

The Problem — and the Fix#

If we use a bare string in the union, we lose the autocomplete on the size property. Instead, we can subtract the known literals from string:

tsx
import React from "react";

/**
 * If we use bare string we lose the autocomplete on size property
 */
type ButtonSize =
    | "xs"
    | "sm"
    | "md"
    | "lg"
    | Omit<string, "xs" | "sm" | "md" | "lg">;

interface ButtonProps {
    size: ButtonSize;
}

export const Button = (props: ButtonProps) => {
    return <button className={`text-${props.size}`}></button>;
};

const Main = () => {
    return (
        <>
            <Button size="sm"></Button>
            <Button size="some other string"></Button>
        </>
    );
};

Because the literal members are still present in the union, the editor suggests "xs" | "sm" | "md" | "lg" while the Omit<string, ...> part keeps arbitrary strings valid.

Wrapping It in a Helper#

Repeating that pattern everywhere is tedious. We can extract it into a reusable type helper:

tsx
/**
 * A type helper for fixing autocomplete issue in union types
 */
type UnionAutocompleteHelper<T extends string> = T | Omit<string, T>;

type ButtonSize2 = UnionAutocompleteHelper<"xs" | "sm" | "md" | "lg">;

interface ButtonProps {
    size: ButtonSize2;
}

export const Button2 = (props: ButtonProps) => {
    return <button className={`text-${props.size}`}></button>;
};

const Main2 = () => {
    return (
        <>
            <Button size="sm"></Button>
            <Button size="some other string"></Button>
        </>
    );
};

Now UnionAutocompleteHelper<T> can be reused for any union of string literals where you want both autocomplete and the freedom to pass an arbitrary string — a small utility that pays off across a whole codebase's developer experience.

Source: typescript-101

#on this page

  • The Problem — and the Fix
  • Wrapping It in a Helper
A Deep Dive Into TypeScript's Infer Keyword olderDecoding URL Parameters with TypeScript: An In-Depth Guidenewer

# related-posts

3 more
  • 01
    TypeScript Advanced ConceptsAug 7, 2023·1 min
  • 02
    Getting Structured Output From LLMs Without the GuessworkJul 7, 2026·5 min
  • 03
    Discriminated Unions: TypeScript's Best Modelling ToolJul 4, 2026·4 min