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>
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.