Skip to content

Numeric enums in the typings can be read by value, but not at runtime #208

Description

@floyd-soomgo

Problem

The typings declare InstallMode, SyncStatus, CheckFrequency and UpdateState as numeric enums. TypeScript therefore accepts reading them by value:

codePush.sync(options, (status) => {
  console.log(codePush.SyncStatus[status]); // type-checks, but always undefined
});

At runtime these are plain objects without reverse keys (SyncStatus and CheckFrequency are object literals in src/CodePush.js; InstallMode and UpdateState come from src/native/NativeCodePush.ts), so the lookup above always gives undefined. An app hit this when it tried to report the sync status a failure happened after: the value was missing from every report.

Why this is not fixed in a patch release

Every way to make the typings and the runtime agree breaks someone. #207 tried the runtime side and was closed for that reason.

  • Add reverse keys at runtime (what a compiled numeric enum does): Object.keys, Object.values, Object.entries, for...in and object spread start returning the numeric keys too. An app that builds a list of statuses from Object.values(codePush.SyncStatus) silently gets the names mixed in. The change shows up only at runtime.
  • Add reverse keys as non-enumerable properties: avoids the above, but it is an unusual shape for an enum, and the reason for it would not be obvious to the next reader.
  • Change the typings to match the runtime: declare each one as a readonly object plus a type of its values, so the reverse lookup becomes a compile error. Comparisons, switch, passing members as options, and annotations like let s: codePush.SyncStatus keep compiling. Code that uses a member as a type, such as let s: codePush.SyncStatus.UP_TO_DATE, has to change to typeof codePush.SyncStatus.UP_TO_DATE.

Proposal

Change the typings in the next major release. Of the options, it is the only one whose breakage surfaces at compile time instead of changing behavior quietly, and it leaves the runtime alone.

DeploymentStatus is a string enum, which TypeScript never reverse-maps, so it is not affected.

Activity

  1. self-assigned this
    on Oct 8, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

bugSomething isn't working

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions