Skip to content

typescript support is broken #930

@pietgk

Description

@pietgk

FYI i had to create opentok-react-native.d.ts

/**
 * Module augmentation for opentok-react-native v2.31.1
 *
 * The package's exports field only exposes OTSession, OTSubscriber,
 * OTSubscriberView, and OTPublisher. The event and handler types used
 * by the Vonage video call code are defined in internal files
 * (NativeOpentok.d.ts, OTSubscriberNativeComponent.d.ts,
 * OTPublisherNativeComponent.d.ts) but not re-exported from the index.
 *
 * With moduleResolution: "bundler", TypeScript enforces the exports field
 * strictly, so we augment the module to expose the types we need.
 *
 * MAINTENANCE: These types mirror opentok-react-native v2.31.1 internals.
 * When upgrading the package, verify these types still match the source
 * definitions in the new version's .d.ts files.
 */
declare module "opentok-react-native" {
  import type React from "react";
  import type { ViewProps } from "react-native";

  // Component exports (JS-only, no upstream .d.ts files)
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
  export const OTSession: React.ComponentType<any>;
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
  export const OTPublisher: React.ComponentType<any>;
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
  export const OTSubscriber: React.ComponentType<any>;
  export const OTSubscriberView: React.ComponentType<ViewProps & { streamId: string }>;

  // From NativeOpentok — session-level event types
  export type ConnectionCreatedEvent = {
    creationTime: string;
    data: string;
    connectionId: string;
    sessionId: string;
  };

  export type ConnectionDestroyedEvent = ConnectionCreatedEvent;

  export type SessionConnectEvent = {
    sessionId: string;
    connection: {
      connectionId: string;
      creationTime: string;
      data: string;
    };
  };

  export type SessionDisconnectEvent = {
    sessionId: string;
  };

  export type StreamCreatedEvent = {
    name: string;
    streamId: string;
    hasAudio: boolean;
    hasCaptions: boolean;
    hasVideo: boolean;
    sessionId: string;
    width: number;
    height: number;
    videoType: string;
    connection: {
      creationTime: string;
      data: string;
      connectionId: string;
    };
    creationTime: string;
  };

  export type StreamDestroyedEvent = StreamCreatedEvent;

  export type SessionOptions = {
    androidZOrder?: string;
    androidOnTop?: string;
    connectionEventsSuppressed?: boolean;
    enableStereoOutput?: boolean;
    enableSinglePeerConnection?: boolean;
    sessionMigration?: boolean;
    iceConfig?: {
      includeServers: string;
      transportPolicy: string;
      filterOutLanCandidates: boolean;
      customServers: {
        urls: string[];
        username?: string;
        credential?: string;
      }[];
    };
    ipWhitelist?: boolean;
    isCamera2Capable?: boolean;
    proxyUrl?: string;
    useTextureViews?: boolean;
  };

  // From OTSubscriberNativeComponent
  export interface SubscriberAudioLevelEvent {
    stream: {
      name: string;
      streamId: string;
      hasAudio: boolean;
      hasCaptions: boolean;
      hasVideo: boolean;
      sessionId: string;
      width: number;
      height: number;
      videoType: string;
      connection: {
        creationTime: string;
        data: string;
        connectionId: string;
      };
      creationTime: string;
    };
    audioLevel: number;
  }

  export interface SubscriberAudioStatsEvent {
    stream: SubscriberAudioLevelEvent["stream"];
    jsonStats: string;
  }

  export interface VideoNetworkStatsEvent {
    stream: SubscriberAudioLevelEvent["stream"];
    jsonStats: string;
  }

  // From OTPublisherNativeComponent
  export type ErrorEvent = {
    code: string;
    message: string;
  };

  // eslint-disable-next-line @typescript-eslint/no-explicit-any
  export type CallbackWithParam<T, E = any> = (param: T) => E;

  // Convenience handler types (removed in v2.31.1 rewrite, still used in app code)
  export type OTSessionEventHandlers = {
    sessionConnected?: (event: SessionConnectEvent) => void;
    sessionDisconnected?: (event: SessionDisconnectEvent) => void;
    sessionReconnecting?: () => void;
    sessionReconnected?: () => void;
    connectionCreated?: (event: ConnectionCreatedEvent) => void;
    connectionDestroyed?: (event: ConnectionDestroyedEvent) => void;
    streamCreated?: (event: StreamCreatedEvent) => void;
    streamDestroyed?: (event: StreamDestroyedEvent) => void;
    error?: (error: unknown) => void;
    otrnError?: (error: unknown) => void;
    signal?: (event: { type: string; data: string; connectionId: string; sessionId: string }) => void;
  };

  export type OTPublisherEventHandlers = {
    audioLevel?: (audioLevel: number) => void;
    error?: (error: unknown) => void;
    otrnError?: (error: unknown) => void;
    streamCreated?: (event: { streamId: string }) => void;
    streamDestroyed?: (event: { streamId: string }) => void;
  };

  export type OTSubscriberEventHandlers = {
    connected?: () => void;
    disconnected?: () => void;
    error?: (error: unknown) => void;
    otrnError?: (error: unknown) => void;
    audioLevel?: (event: SubscriberAudioLevelEvent) => void;
    audioNetworkStats?: (event: SubscriberAudioStatsEvent) => void;
    videoNetworkStats?: (event: VideoNetworkStatsEvent) => void;
    videoDataReceived?: () => void;
    videoDisabled?: (event: { stream: SubscriberAudioLevelEvent["stream"]; reason: string }) => void;
    videoDisableWarning?: () => void;
    videoDisableWarningLifted?: () => void;
    videoEnabled?: (event: { stream: SubscriberAudioLevelEvent["stream"]; reason: string }) => void;
    rtcStatsReport?: (event: { stream: SubscriberAudioLevelEvent["stream"]; jsonStats: string }) => void;
    captionReceived?: (event: { stream: SubscriberAudioLevelEvent["stream"]; text: string; isFinal: boolean }) => void;
  };

  export type OTSessionSessionOptions = SessionOptions;
}

Context

The package has fundamentally broken TypeScript support.

Evidence

  1. The four main components are untyped JavaScript

OTSession.js, OTPublisher.js, OTSubscriber.js, OTSubscriberView.js are plain .js class components using
PropTypes — zero TypeScript. The entry point src/index.tsx has // @ts-nocheck with the comment "Ignore
these typeless modules for now".

  1. The shipped index.d.ts is broken

The generated lib/typescript/module/src/index.d.ts tries to re-export from ./OTSession, ./OTPublisher,
etc. — but no .d.ts files exist for those modules. The components resolve to implicit any under both
resolution modes.

  1. Internal types exist but are NOT accessible

The package ships .d.ts files for native codegen specs:

  • NativeOpentok.d.ts — session event types (SessionConnectEvent, etc.)
  • OTPublisherNativeComponent.d.ts — publisher event types
  • OTSubscriberNativeComponent.d.ts — subscriber event types

But these are not re-exported from the index, and the exports field only exposes "." — so they're
inaccessible via import { ... } from "opentok-react-native".

  1. No @types/opentok-react-native exists on npm

  2. Many needed types don't exist in the package at all

These are custom types our app defines because the package never had them:

  • Handler types: OTSessionEventHandlers, OTPublisherEventHandlers, OTSubscriberEventHandlers
  • Convenience aliases: StreamCreatedEvent, StreamDestroyedEvent, ConnectionCreatedEvent,
    ConnectionDestroyedEvent
  • Utility types: CallbackWithParam, OTSessionSessionOptions
  1. Even existing internal types have naming mismatches

│ Our type │ Package internal type │ Match? │
│ ConnectionCreatedEvent │ ConnectionEvent │ Different structure │
│ StreamCreatedEvent │ StreamEvent (alias for Stream) │ Different structure │
│ SubscriberAudioLevelEvent │ exists but uses Float not number │ Close but not exact │

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions