TobiDevloft
TobiDevloft

Reputation: 301

How to I specify a method filtering an array for a certain type of element?

I'm trying to implement a function which splits an array consisting of different elements into an array of elements of a certain type (specified in the function call). This is the simplified code:

export enum GenericElementType {
  ONE = 'type one',
  TWO = 'type two'
}

export interface TypeA {
  id: string;
  type: GenericElementType.ONE;
}

export interface TypeB {
  id: string;
  type: GenericElementType.TWO;
}

export type ElementType = TypeA | TypeB;
const arrayOfElements: (DFDElementType)[] = [];

function filterElementsOfCertainType<T extends ElementType>
  (elements: (ElementType)[], type: GenericElementType): T[] {
  return elements.filter((element: ElementType) => element.genericType === type);
}

This results in an error, because not every element in ElementType matches the return type T. How would I go about implementing this function correctly typed?

Here is a Playground link.

Another Playground link using generic typing.

Upvotes: 0

Views: 77

Answers (2)

Vlad Strukelj
Vlad Strukelj

Reputation: 124

Assuming your "specific types" are the ones you gave, returning ElementType[], and compare the element.type with type. Think that should work. Cheers

Edit:

I think you should think of the pattern. From your last playground. elementOfTypeA: TypeA[] should be elementOfTypeA: ElementType[], you already give the required type as parameter. To put it in simpler logic, this will never work:

interface  person{
  id: string;
}
type teacher = person | number;

const randomVariable: person = 3;

although, this will:

interface  person{
  id: string;
}
type teacher = person | number;

const randomVariable: teacher = 3;

last resort:

function filterElementsOfCertainType<T extends ElementType>
  (elements: any[], type: GenericElementType): T[] {
  return elements.filter((element: T) => element.type !== undefined && element.type === type);
}

then const elementOfTypeA: TypeA[] = filterElementsOfCertainType([a, b, c], GenericElementType.TWO); will work.

it also seems to be the way the typescript documentation wants you to do it. https://www.typescriptlang.org/docs/handbook/advanced-types.html

check "User-Defined Type Guards". Cheers mate.

playground

Upvotes: 1

alex kucksdorf
alex kucksdorf

Reputation: 2633

This playground should work. However, this is the correct typing:

function filterElementsOfCertainType<T extends ElementType>
  (elements: T[], type: GenericElementType): T[] {
  return elements.filter((element: T) => element.type === type);
}

Upvotes: 0

Related Questions