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
}
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)