Although this question was posted a year ago, for those who are just joining us now, here is the information you need.
I'm not sure how I overlooked this in the documentation, but since we're all in the same boat here, let's explore what's happening (starting from your code).
type Types = 'text' | 'date' | 'articles' | 'params';
type MyExperiment<Type extends Types> = { t : Type };
// The parentheses around "infer U" can be removed as they serve no purpose here
type MyExperimentsUnion = Types extends infer U ? MyExperiment<U> : never;
// Type 'U' does not satisfy the constraint 'Types'.
In your code, you're only using the infer
keyword to capture Types
, but that doesn't provide TypeScript with any information about U
. This might lead you to wonder why:
type foo = Types extends infer U ? U : never;
// foo will display 'text' | 'date' | 'articles' | 'params'
You might ask yourself, "Isn't U
then of type
'text' | 'date' | 'articles' | 'params'
? Why can't it be assigned to
MyExperiment<>
?". In my opinion, the union type is resolved only at the end of the conditional statement, so it isn't technically available when assigning it as a type parameter to
MyExperiment<>
.
If you wish to use infer
and distribute the type properly, you'll need an additional condition to constrain U
at that point to ensure it's used correctly as a type parameter in MyExperiment<>
.
type MyExperimentsUnion =
Types extends infer U ?
U extends Types ?
MyExperiment<U>
: never
: never;
// MyExperiment<"text"> | MyExperiment<"date"> | MyExperiment<"articles"> | MyExperiment<"params">
Alternatively, your example could also be achieved like this
type MyExperimentsUnion<T extends Types = Types> = T extends any ? MyExperiment<T> : never;
// Using MyExperimentsUnion without a type parameter will result in
// MyExperiment<"text"> | MyExperiment<"date"> | MyExperiment<"articles"> | MyExperiment<"params">
* This is purely speculative on my part, as I haven't delved deeply into how TypeScript evaluates these scenarios.