2

I am trying to make well typed function for getting only distinct values of object's property in array. So it works like that

type Employee = { work: WorkEnum; name: string };
const arg1: Employee[] = [{ name: "kornad", work: WorkEnum.Doctor}, { name: "Adam", work: WorkEnum.FrontEndDeveloper}]

const result1: WorkEnum[] = getDistinct(arg1, 'work')
const result1: string[] = getDistinct(arg1, 'name')

so function needs to detect possible keys for seconds argument (that I've managed to do) and type of the value (I don't know how to do this one)

Here is my function

type ArrayObject<V> = {
  [key: string]: V;
};

function getDistinct<V, T extends ArrayObject<V>>(
  data: T[],
  property: keyof T
): V[] {
  const allValues = data.reduce((values: V[], current) => {
    if (current[property]) {
      values.push(current[property]);
    }
    return values;
  }, []);

  return [...new Set(allValues)];
}

const arrayOfData: { xxx: string; qwe: string | number }[] = [
  { xxx: 'asd', qwe: 43 },
  { xxx: 'asd', qwe: 'dsadas' },
];

const res = getDistinct(arrayOfData, 'xxx'); // res: unknown[], why not string[] ??????????

So Typescript cannot figure it out that res should be string[] instead of this I am getting here unknown[]. How can I fix it?

1 Answer 1

2

As far as I can tell, the ArrayObject definition and function return type are not correct.

This will work:

function getDistinct<T, K extends keyof T>(data: T[], property: K): T[K][] {
  const allValues = data.reduce((values: T[K][], current) => {
    if (current[property]) {
      values.push(current[property]);
    }
    return values;
  }, []);

  return [...new Set(allValues)];
}

const arrayOfData: { xxx: string; qwe: string | number }[] = [
  { xxx: 'asd', qwe: 43 },
  { xxx: 'asd', qwe: 'dsadas' },
];

const res1 = getDistinct(arrayOfData, 'xxx'); // string[]
const res2 = getDistinct(arrayOfData, 'qwe'); // (string | number)[]

The important part is to define your property as a keyof T, and the return type as the type associated with that property (T[K]), or in this case, an array of that type (T[K][]).


TypeScript Playground link

Sign up to request clarification or add additional context in comments.

5 Comments

Side note: probably better to reduce immediately to a Set, without creating the intermediate array.
is there a way to exclude undefined from the return type?
The example you gave does not have undefined in the return type...
but if we have a type like that { xxx?: string } and we are taking that xxx property is there a way to have a return type only as string[]?
You can exclude null and undefined using NonNullable,

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.