Home > Back-end >  Is it possible to remove a wider type from an literal union in Typescript?
Is it possible to remove a wider type from an literal union in Typescript?

Time:01-11

I'm working with React and Typescript, building a custom input component and I wish to cleanup the allowed values from type attribute in the input element to prevent unintended used as 'button' and 'hidden'.

The type attribute have the type of HTMLInputTypeAttribute that's an union type that ends up with (string & {}). I don't want the component to receive type values that are not literal described in the union.

Using the Exclude utility type results in never since all literal types extends from string

I've already looked at other questions like How can I remove a wider type from a union type without removing its subtypes in TypeScript? but as their intent was not necessarily related to a previously established union, none of the answers met my need

Is this somehow possible?

CodePudding user response:

You need to use Distributive conditional types

type Union = 'a' | 'b' | string & {}

type GetLiteral<Type extends string | number, Value> =
    Value extends Type
    ? (Type extends Value
        ? never
        : Value)
    : never

type ObtainLiterals<T> = T extends infer R ? GetLiteral<string, R> : never

// 'a' | 'b'
type Test = ObtainLiterals<Union>

Playground

GetLiteral expects a type of union which corresponds to Type and a value which corresponds to Value generic.

ObtainLiterals - distributes a union. It means that each element in the union is called with GetLiteral which at the end produces 'a'|'b'|never. And never is always getting removed from the union.

  • Related