geovanisouza92
geovanisouza92

Reputation: 179

Type based on union type option

I would like to create an object where the property name is a value from a union type, and the type of the value based on that prop type, e.g:

type Direction =
  "horizontal"
  | "vertical"
  | "diagonal"
  ;

// Choose one of this types based on Direction option
interface HorizontalData { foo: number; }
interface VerticalData { bar: string; }
interface DiagonalData { baz: boolean; }

type Result<D extends Direction> = {
  data: << type based on D value >>;
};

Upvotes: 1

Views: 293

Answers (1)

jcalz
jcalz

Reputation: 327774

Yes, this is possible. You can define a type which represents the mapping from each property name to the corresponding ***Data, like this:

type DirectionMapping = {
  "horizontal": HorizontalData
  "vertical": VerticalData
  "diagonal": DiagonalData
};

(Aside: If you want you can remove your original definition of Direction and replace it with:

type Direction = keyof DirectionMapping;

which amounts to the same thing, but keeps your code DRY.)

Note that you will never need an instance of DirectionMapping at runtime. Instead you use it to look up the output type in the definition of Result:

type Result<D extends Direction> = {
  data: DirectionMapping[D]; // uses indexed-access/lookup type 
};

And test that it behaves as expected:

const horz: Result<"horizontal"> = { data: { foo: 3 } }; // okay
const vert: Result<"vertical"> = { data: { foo: 3 } }; // error 

Hope that helps. Good luck!

Upvotes: 2

Related Questions