Home > Enterprise >  TypeScript copy existing interface but change type on one property
TypeScript copy existing interface but change type on one property

Time:09-22

I have this interface:

interface IInternalListener {
  element: HTMLElement,
  id: string,
  type: string,
  listener: EventListenerOrEventListenerObject,
  useCapture: boolean
}

And I also want to use this interface:

interface IListener {
  element: HTMLElement,
  id: string | number,
  type: string,
  listener: EventListenerOrEventListenerObject,
  useCapture: boolean
}

The only difference being the type for id. I want to employ DRY (Don't Repeat Yourself)

How can I create this without copy paste. A mapped type seems the way to go but in this answer here they are mapping all the props - Typescript: how do you create a Copy of a type but change the property typeings

I only want to change one prop. Anyone know how to do this? I don't have to use mapped types, any viable solution is fair game. TIA

CodePudding user response:

There are a few ways to do this.

Way 1

Extract the common logic into a third interface the other two extend:

interface IWhatever {
  element: HTMLElement,
  type: string,
  listener: EventListenerOrEventListenerObject,
  useCapture: boolean
}

interface IListener extends IWhatever {
  id: string
}

interface IInternalListener extends IWhatever {
  id: string | number
}

Way 2

As Robby Cornelissen points out in the comments, you can use a generic:

interface IListener<T> {
  id: T
  element: HTMLElement,
  type: string,
  listener: EventListenerOrEventListenerObject,
  useCapture: boolean
}

Way 3

Lets say you don't own the IListener interface and can't change it but you want to reuse a lot of it for your other interface:

interface IInternalListener extends Omit<IListener, 'id'> {
  id: string | number
}

CodePudding user response:

You can use extends and Omit utility type together.

Example

interface IInternalListener {
  element: HTMLElement,
  id: string,
  type: string,
  listener: EventListenerOrEventListenerObject,
  useCapture: boolean
}

interface IListener extends Omit<IInternalListener, 'id'> {
    id: string | number
}

Basically, we will remove the id property and add it back with the preferred type you need.

  • Related