Home > database >  limit the type of one argument based on anther argument in typescript function
limit the type of one argument based on anther argument in typescript function

Time:10-06

interface INavigation {
  children: string[];
  initial: string;
}

function navigation({ children, initial }: INavigation) {
  return null
}

I have a function that looks something like the above. I'm trying to see if there is a way to limit the initial input to only the list from the children array.

For example,

// should work
navigation({ children: ["one", "two", "three"], initial: "one" })
navigation({ children: ["one", "two", "three"], initial: "two" })

// should throw a type error
// Type 'four' is not assignable to type 'one' | 'two' | 'three'.
navigation({ children: ["one", "two", "three"], initial: "four" })

is there a way to do this using typescript?

I can only think of throwing an error in the function

function navigation({ children, initial }: INavigation) {
   
  if (!children.includes(initial)) {
    throw new Error(`${initial} is invalid. Must be one of ${children.join(',')}.`
  }
  return null
}

TS Playground

CodePudding user response:

You need to make your INavigation type generic so it can capture some specific set of strings.

interface INavigation<Children extends readonly string[]> {
  children: Children;
  initial: Children[number];
}

Here Children is an array of some sort of strings and is assigned as the type of the children property. And initial is the member type of that array.

And then make your function generic to provide that type:

function navigation<Children extends readonly string[]>(
  { children, initial }: INavigation<Children>
) {
  return null
}

Then add as const to your sample data to ensure these get inferred as string literal types instead of just string.

// should work
navigation({ children: ["one", "two", "three"], initial: "one" } as const)
navigation({ children: ["one", "two", "three"], initial: "two" } as const)

// should throw a type error
// Type 'four' is not assignable to type 'one' | 'two' | 'three'.
navigation({ children: ["one", "two", "three"], initial: "four" } as const)

See playground

  • Related