Your question is similar to this question. There's no single type Props
type you can define that accepts exactly objects of the form {options, value}
where the value
is one of the options
. You could start by introducing a type parameter O
for the valid options:
interface Option<O extends string> {
name: string;
value: O;
}
interface Props<O extends string> {
options: Option<O>[];
value?: O;
}
but then you run into two problems:
- You can't write a single type that means "
Props<O>
for some O
". This would be an existential type, which TypeScript currently doesn't support. Props<any>
doesn't work: it places no restriction on the options and the values.
- If a caller manually specifies
O
, there's no way to enforce that options
contains all the values of O
.
In light of these problems, the closest you can come is to write a generic function that you can call with an {options, value}
object literal, such that type inference will succeed if the value is one of the options and fail if it isn't. This may or may not be useful depending on the structure of the rest of your code.
// Building on `Option` and `Props` defined above.
// Needed to prevent widening when storing the options array in a local
// variable. If the options array is passed directly to `checkProps`,
// this isn't needed.
function asOptions<O extends string>(options: Option<O>[]) {
return options;
}
const options = asOptions([
{ name: 'Option1', value: 'option1' },
{ name: 'Option2', value: 'option2' },
]);
// We need to use two type parameters to detect errors. If we use just
// `O`, then TypeScript will try to be helpful and infer `O` to be the
// union of the options and the value.
function checkProps<O extends string, O1 extends O>(
props: { options: Option<O>[], value?: O1 }) {
return props;
}
let myProps1 = checkProps({
options: options,
value: "option1" // OK
});
let myProps2 = checkProps({
options: options,
value: "option3" // Error
});
let myProps3 = checkProps({
options: [
{ name: 'Option1', value: 'option1' },
{ name: 'Option2', value: 'option2' },
],
value: "option3" // Error
});