Home > OS >  How to iterate on array that implements one of two interfaces in typescript
How to iterate on array that implements one of two interfaces in typescript

Time:12-21

The goal is to find a reusable way to filter out an array of items, the array will implement one of two interfaces

Showing a code example of what I wanna do would be best:

interface IDuration {
  start: number;
  end: number;
}

interface IRelativeDuration {
  relativeStart: number;
  relativeEnd: number;
}

export const enforceBoundries = (
  point: number,
  items: Array<IDuration> | Array<IRelativeDuration>,
): void => {

  let startKey: string
  let endKey: string

  // **CAN'T FIGURE THIS OUT**
  if(/* iDuration */) {
    startKey = 'start'
    endKey = 'end'
  } else {
    startKey = 'relativeStart'
    endKey = 'relativeEnd'
  }

  items.forEach(item => {
    if(item[startKey] > point) {
      //....
    }
  })
}

The answer most likely would be in Generic Constraints, but I am not that good with typescript

Tried many conditions in the if but can't figure out a way that would make the app compiles

CodePudding user response:

You can try to use typeof to know if the type of item. Then you have to cast it to its type.

CodePudding user response:

As far as i know, there is now way to check if a json-object matches a interface at runtime. There a no interfaces at Javascript, at all.

"typeof" would not work either because the result would always be "object"

So a solution could be to utilise Object.keys() and check if all required properties are present at the object:

interface IDuration {
    start: number;
    end: number;
}

interface IRelativeDuration {
    relativeStart: number;
    relativeEnd: number;
}

export const enforceBoundries = (
    point: number,
    items: Array<IDuration> | Array<IRelativeDuration>,
): void => {
    items.forEach((item: IDuration | IRelativeDuration) => {
        const props = Object.keys(item) // get all keys from item-object
        let startValue = null

        // check if item meets one of the two interfaces
        if (props.includes("start") && props.includes("end")) {
            // it is a IDuration
            startValue = (item as IDuration).start

        } else if (props.includes("relativeStart") && props.includes("relativeEnd")) {
            // it is a IRelativeDuration
            startValue = (item as IRelativeDuration).relativeStart
        } else {
            // no IDuration and no IRelativeDuration
            throw new Error("something went wrong...");
        }

        if (startValue === null)
            throw new Error("startValue should never be null at this point...");


        if (startValue > point) {
            //....
        }
    })
}
  • Related