i have a function which accept an array and a field params, but i want to restrict field's type to an union type which describe array's all field value, like this:
interface item {
name: string,
value: number
}
const fn = (arr: item[], name: any) => {
// if arr = [{name: 'a', value: 1}, {name: 'b', value: 2}]
// don't want name have any type
// i neeed name is a union type 'a' | 'b'
}
Maybe this need generic type, but i don't know how to do.
CodePudding user response:
You can make Item
generic.
interface Item<N> {
name: N,
value: number
}
And use it in the function declaration like this:
const fn = <T extends Item<N>, N extends string>(arr: T[], name: T["name"]) => {
}
When you call the function, T[name]
will be the union of the name
values.
fn([{name: 'a', value: 1}, {name: 'b', value: 2}], "a")
fn([{name: 'a', value: 1}, {name: 'b', value: 2}], "b")
fn([{name: 'a', value: 1}, {name: 'b', value: 2}], "c") // Error
CodePudding user response:
Maybe this need generic type
Yes, exactly. You use a generic type parameter for the type of the name
property, and another type parameter for the array elements that must have a name
property, like this:
const fn = <NameType, ElementType extends { name: NameType }>(
arr: ElementType[],
name: NameType
) => {
// ...
};
Then this works, because they match:
fn([ { name: "a", value: 1 }, { name: "b", value: 2 }, ], "c");
...but this gives an error as desired, because they don't:
fn([ { name: "a", value: 1 }, { name: "b", value: 2 }, ], 42);
// Error: Type 'string' is not assignable to type 'number'. (2322)
You've mentioned an item
interface (idiomatically it would be Item
, not item
), but not used it in relation to fn
, but if arr
is supposed to be of Item
elements, you can make Item
generic and then use it instead of { name: NameType }
in the extends
:
interface Item<NameType = string, ValueType = number> {
name: NameType;
value: ValueType;
}
const fn = <NameType, ElementType extends Item<NameType>>(
arr: ElementType[],
name: NameType
) => {};