Typescript type restriction based on another value – how to apply this restriction in an array

I wasn’t sure how to word this question. I have a scenario where I have an object. Key1 is the name, key2 is options. Options type depends on the value of name.

This works ok, thanks to:

export type Option1 = {
  one: string;
};

export type Option2 = {
  two: string;
};

export type Name = 'first' | 'second';

export type Options<TName extends Name> = TName extends 'first'
  ? Option1
  : TName extends 'second'
  ? Option2
  : never;

type Baz<TName extends Name> = { name: TName, opts: Options<TName> }

Now I wish to use this in an object.

type MyObj = {
   foo: boolean,
   bar: string,
   baz: Baz[]
}

The goal is to do something like this:

const test: MyObj = {
   baz: [ { name: 'first': opts: .. }, { name: 'second': opts: .. }]
}

With it being all typed correctly. If name is ‘first’, then opts is typed to only have key one. However, MyObj complains that I need to pass in a generic type to Baz, which makes sense, but I’m not sure what or how. I tried type Baz<TName extends Name = Name> to default it, but this just makes all my values a union of all options, where opts is one and two keys.

How can i restrict this type?

>Solution :

You can achieve it in a very simple way using union type:

export type Option1 = {
  one: string;
};

export type Option2 = {
  two: string;
};

export type NameWithOptions =
  | { name: 'first'; opts: Option1[] }
  | { name: 'second'; opts: Option2[] };

type MyObj = {
  foo: boolean;
  bar: string;
  baz: NameWithOptions[];
};

const test: MyObj = {
  baz: [
    { name: 'first', opts: [{ one: 'one' }] },
    { name: 'second', opts: [{ two: 'two' }] },
  ],
};

Leave a Reply