react-native-track-player icon indicating copy to clipboard operation
react-native-track-player copied to clipboard

feat: type support for event listener

Open Spice-Z opened this issue 2 years ago • 1 comments

I want event listener's parameter type, but that was any! So

  • Defined interface EventListenerProp
  • Added generics to function addEventListener to enable type inference in listener function
    • This Generics receives enum Event value

Now, listener's param is not any! (from example code) スクリーンショット 2022-07-10 19 00 41

(Generics might be removed, but I don't figure out how to do it. :sob:)

Spice-Z avatar Jul 10 '22 10:07 Spice-Z

@Spice-Z any updates on this PR? I'd love to merge it if we can fix the BC issue.

jspizziri avatar Aug 08 '22 15:08 jspizziri

We can infer the type instead. Note that the following also improves the type for events that do not expect an event object.

function addEventListener<T extends Event>(
  event: T,
  listener: EventDataByEvent[T] extends never ? () => void : (event: EventDataByEvent[T]) => void,
) {
  return emitter.addListener(event, listener)
}

export interface EventDataByEvent {
  [Event.PlaybackState]: {
    state: State
  }
  [Event.PlaybackError]: {
    code: string
    message: string
  }
  [Event.PlaybackQueueEnded]: {
    track: number
    position: number
  }
  [Event.PlaybackTrackChanged]: {
    track: number
    position: number
    nextTrack: number
  }
  [Event.PlaybackMetadataReceived]: {
    source: string
    title: string | null
    url: string | null
    artist: string | null
    album: string | null
    date: string | null
    genre: string | null
  }
  [Event.PlaybackProgressUpdated]: {
    position: number
    duration: number
    buffer: number
    track: number
  }
  [Event.RemotePlay]: never
  [Event.RemotePlayId]: {
    id: string
  }
  [Event.RemotePlaySearch]: {
    query: string
    focus: string
    title: string
    artist: string
    album: string
    date: string
    playlist: string
  }
  [Event.RemotePause]: never
  [Event.RemoteStop]: never
  [Event.RemoteSkip]: {
    index: number
  }
  [Event.RemoteNext]: never
  [Event.RemotePrevious]: never
  [Event.RemoteJumpForward]: {
    interval: number
  }
  [Event.RemoteJumpBackward]: {
    interval: number
  }
  [Event.RemoteSeek]: {
    position: number
  }
  [Event.RemoteSetRating]: {
    rating: boolean | number
  }
  [Event.RemoteDuck]: {
    paused: boolean
    permanent: boolean
  }
  [Event.RemoteLike]: never
  [Event.RemoteDislike]: never
  [Event.RemoteBookmark]: never
}
`

puckey avatar Aug 10 '22 13:08 puckey

@puckey I like that approach, but just to be clear. This would require a generic argument to be passed into addEventListener still would it not? Meaning addEventListener(...) would cause a ts error since you're not specifying an argument?

jspizziri avatar Aug 10 '22 15:08 jspizziri

@jspizziri No it wouldn't – the type is inferred:

Screenshot 2022-08-10 at 16 11 50

puckey avatar Aug 10 '22 15:08 puckey

See here for my additional changes to this PR: https://github.com/doublesymmetry/react-native-track-player/pull/1640

puckey avatar Aug 10 '22 15:08 puckey

closing in favor of the new PR.

jspizziri avatar Aug 10 '22 15:08 jspizziri