Skip to content

Module-scope the platform type surface: make @nativescript/types export ObjC/Java names instead of declaring them ambient #11524

Open

Description

@aleclarson

Proposal

Flip the layering in one pass: the module becomes the source of truth, and the ambient globals become a thin compat shim over it.

Today types-ios/types-android declare ~10k ObjC/Java names as globals (UIApplication, java.io, android.app, interop…), and @nativescript/core's platform declarations bind them ambiently. Instead:

  1. Move the generated surface into modules. types-ios and types-android ship their decls as module exports — export declare class UIView, export import io = java.io, etc. The generator already emits flat files; this is a header/footer rewrite plus export prefixes, not a semantic change.
  2. Core's platform decls import, not assume. index.ios.d.ts gets import type { UIView } from '@nativescript/types-ios' for each referenced platform name — mechanical, one import type line per file (the referenced names are greppable).
  3. Recreate the ambient as an opt-in shim. Keep types: ["@nativescript/types"] working via a single globals.d.ts:
declare global {
  type UIView = import('@nativescript/types-ios').UIView
  var UIApplication: typeof import('@nativescript/types-ios').UIApplication
  // ...generated for the full surface
}
export {}

Programs with the types entry see the exact same globals as today — zero breaking change. Programs without it get nothing ambient and core still typechecks precisely, because its decls bind the module directly.

That's the whole PR. One mechanical rewrite across types-ios, types-android, and the platform .d.ts emission in core — no phased rollout, no dual maintenance.

Why

  • Collisions stop being file-order-dependent. Two ambient declare class NSObject in one program is first-wins; any package carrying its own ObjC surface (e.g. a hand-maintained AppKit layer for @nativescript/macos-node-api, which ships no generated types) currently fights upstream for the same name and the outcome depends on declaration order the tsconfig author can't fully control.
  • Multi-platform programs become possible. Checking iOS + Android + other native code in one tsc run means one global namespace — module-scoped platform types eliminate the collision class entirely.
  • Opt-out stops silently degrading. Today a program without types: ["@nativescript/types"] doesn't error — skipLibCheck degrades core's platform members (nativeViewProtected: UIView) to any. With module binding, core is precisely typed whether or not the ambient shim is loaded.
  • The escape hatch gets visible. Platform-native names become explicit imports — discoverable, greppable, lint-enforceable — instead of unexplained globals.

(Verified: import '@nativescript/core' doesn't pull the ambient — index.d.ts only references global-types.d.ts. The ambient enters exclusively via types://// entries, so the opt-in boundary already exists; this change just makes the module form the canonical one.)

Scope

  • types-ios, types-android: emit module form + generated globals.d.ts shim.
  • @nativescript/core: platform .d.ts emission gains import type lines; runtime untouched — the values are runtime globals, only declarations move.
  • Docs: types: ["@nativescript/types"] stays the recommended ambient opt-in; apps that want strict module scoping simply omit it.

Happy to drive the PR — the rewrite is scriptable and the verification is the existing test suite plus a program compiled without the types entry.

Activity

  1. NathanWalker commented on Oct 14, 2026

    @NathanWalker
    Contributor

    Great topics here, we'll link in with these - quite a few ideas have been shared on this: NativeScript/rfcs#45

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions