Home > Blockchain >  Return type of a single property from type T in TypeScript
Return type of a single property from type T in TypeScript

Time:02-05

I have a helper function that I'm porting from JavaScript:

function extractDistinct(data, fieldName) {
  const uniques = data.reduce(
    (set, x) => set.add(x[fieldName]), new Set()
  );
  return [...uniques];
}

This function simplify extract a list of unique values for property fieldName in a an array of items. While the JavaScript code actually allows for a collection of possibly different data types —as long as they have the intended field— I guess the version I'm trying to get for TypeScript would limit to an array of a single type.

Here's what I have so far:

function extractDistinct<T>(data: T[], fieldName: keyof T): unknown[] {
  const uniques = data.reduce((set, x) => set.add(x[fieldName]), new Set());
  return [...uniques];
}

It works in that the TS compiler is checking to make sure fieldName is indeed a property of T but I have to cast the whole thing as the intended type which is a bit clunky:

const people: Person[] = .... // doesn't matter where it comes from.
const hairColor = extractDistinct(people, 'hair_color') as string[]);

I currently have it as returning unknown[] but I'm trying to return the type declared for this key/field in type T. How can that be achieved?

CodePudding user response:

You want extractDistinct() to be generic in the string literal type K of the fieldName parameter as well as in the type T of the elements of data:

function extractDistinct<T, K extends keyof T>(data: T[], fieldName: K): T[K][] {
  const uniques = data.reduce((set, x) => set.add(x[fieldName]), new Set<T[K]>());
  return [...uniques];
}

This uses the indexed access type T[K] to represent the property type of T at key K. That compiles with no error, and now you get your desired behavior:

interface Person {
  hair_color: string;
  number_of_limbs: number;
  actually_three_hedgehogs_in_a_trenchcoat: boolean;
}
declare const people: Person[];

const hairColor = extractDistinct(people, 'hair_color');
// const hairColor: string[]

const numberOfLimbs = extractDistinct(people, 'number_of_limbs');
// const numberOfLimbs: number[]

Playground link to code

  • Related