Home > front end >  how to create a union type which describe all values from an array's field?
how to create a union type which describe all values from an array's field?

Time:10-12

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

Playground

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)

Playground link

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
) => {};

Playground link

  • Related