Skip to content

Commit 19ae03d

Browse files
sunnylqmclaude
andauthored
fix(types): ship compiled .d.ts so app tsconfigs never check our sources (#698)
* fix(types): compile cleanly under app tsconfigs on RN 0.88 package.json `types` points at src/index.ts, so apps type-check this package's sources and skipLibCheck does not apply. Two errors surfaced after upgrading to 10.62.0: - client.ts: the private emitError delegate was never read (TS6133 under noUnusedLocals). Remove it; tests now call reporter.emitError directly. - clientDownload.ts: calling addListener on the union of DeviceEventEmitter and the NativeEventEmitter is not callable with RN 0.88 types (TS2349). Branch into two calls; emitted JS behaves the same. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * build(types): publish compiled declarations instead of the TS sources package.json `types` pointed at src/index.ts, so an app's tsc compiled this package's sources under the app's own tsconfig (noUnusedLocals, ...) and React Native version, where skipLibCheck does not reach. Emit declarations to lib/typescript with tsc --emitDeclarationOnly (tsconfig.build.json), point `types` at them and ship them; `main` stays src/index for Metro. prepack, the lint workflow and the publish action build them, and check-packlist requires the `types` file. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * ci: don't require the type declarations in the C++ job's packlist check Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
1 parent d16715c commit 19ae03d

11 files changed

Lines changed: 55 additions & 13 deletions

File tree

‎.github/actions/publish-npm/action.yml‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,12 @@ runs:
105105
shell: bash
106106
run: test -f harmony/pushy.har
107107

108+
# npm publish rebuilds them in prepack; build them here too so the
109+
# file-list check below sees lib/typescript.
110+
- name: Build type declarations
111+
shell: bash
112+
run: bun build:types
113+
108114
- name: Verify publish file list
109115
shell: bash
110116
run: node scripts/check-packlist.js --release

‎.github/workflows/lint.yml‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,5 +39,10 @@ jobs:
3939
- name: Run lint
4040
run: bun lint
4141

42+
# check-packlist.js requires the emitted declarations that
43+
# package.json `types` points at.
44+
- name: Build type declarations
45+
run: bun build:types
46+
4247
- name: Verify publish file list
4348
run: node scripts/check-packlist.js

‎.gitignore‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,9 @@ local.properties
4242
node_modules/
4343
npm-debug.log
4444

45+
# Type declarations emitted by `bun build:types` (published, not committed)
46+
lib/
47+
4548
Example/**/.update
4649
Example/**/.pushy
4750
Example/**/.e2e-artifacts

‎package.json‎

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,11 @@
33
"version": "10.62.0",
44
"description": "Hot update (OTA) for React Native with Hermes-optimized diff patches, crash rollback and staged rollout. A CodePush alternative for iOS, Android and HarmonyOS.",
55
"main": "src/index",
6-
"types": "src/index.ts",
6+
"types": "lib/typescript/index.d.ts",
77
"files": [
88
"src",
99
"!src/__tests__",
10+
"lib/typescript",
1011
"android/src",
1112
"!android/src/test",
1213
"android/lib",
@@ -45,8 +46,9 @@
4546
"LICENSE"
4647
],
4748
"scripts": {
48-
"prepack": "bun submodule && bun lint",
49+
"prepack": "bun submodule && bun lint && bun build:types",
4950
"lint": "biome check src && tsc --noEmit && node scripts/check-harmony-types.js && node scripts/check-native-spec-parity.js && bun scripts/generate-contract.ts --check && node scripts/check-readme-options.js",
51+
"build:types": "rm -rf lib/typescript && tsc -p tsconfig.build.json",
5052
"contract": "bun scripts/generate-contract.ts",
5153
"lint:harmony": "node scripts/check-harmony-types.js",
5254
"submodule": "git submodule update --init --recursive",

‎scripts/check-packlist.js‎

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
// must and must not be there. Run in lint CI and right before `npm publish`
55
// (with --release, which additionally requires the Harmony HAR).
66
const { execFileSync } = require('child_process');
7-
const { files: filesField } = require('../package.json');
7+
const { files: filesField, types } = require('../package.json');
88

99
const release = process.argv.includes('--release');
1010
// Also compile the packed native sources (needs the submodules and a C
@@ -56,6 +56,10 @@ const required = [
5656
'package.json',
5757
'src/index.ts',
5858
'src/NativePushy.ts',
59+
// The declarations apps type-check against (bun build:types emits them).
60+
// --compile runs in test.yml's C++ job, which has no JS toolchain to
61+
// build them; the lint workflow and the publish action check them.
62+
...(compile ? [] : [types]),
5963
'android/build.gradle',
6064
'android/src/main/java/cn/reactnative/modules/update/UpdateContext.java',
6165
'ios/RCTPushy/RCTPushy.mm',

‎src/__tests__/client.test.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,7 @@ describe('Pushy server config', () => {
174174
async () => {}
175175
);
176176

177-
(client as any).emitError(new Error('offline'), 'errorChecking');
177+
(client as any).reporter.emitError(new Error('offline'), 'errorChecking');
178178
client.reportInvalidUpdateOnce('noArtifact', 'h2');
179179

180180
expect(report).toHaveBeenCalledWith(

‎src/__tests__/provider.render.test.tsx‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,7 @@ describe('UpdateProvider rendering', () => {
199199
// Real client contract under the default throwError:false — the error is
200200
// emitted to onError listeners and checkUpdate resolves undefined.
201201
client.checkUpdate.mockImplementation(async () => {
202-
client.emitError(checkError, 'errorChecking');
202+
(client as any).reporter.emitError(checkError, 'errorChecking');
203203
return undefined;
204204
});
205205

@@ -244,7 +244,7 @@ describe('UpdateProvider rendering', () => {
244244
});
245245
const checkError = new Error('offline');
246246
client.checkUpdate.mockImplementation(async () => {
247-
client.emitError(checkError, 'errorChecking');
247+
(client as any).reporter.emitError(checkError, 'errorChecking');
248248
return undefined;
249249
});
250250

@@ -265,7 +265,7 @@ describe('UpdateProvider rendering', () => {
265265
dismissErrorAfter: 20,
266266
});
267267
client.checkUpdate.mockImplementation(async () => {
268-
client.emitError(new Error('offline'), 'errorChecking');
268+
(client as any).reporter.emitError(new Error('offline'), 'errorChecking');
269269
return undefined;
270270
});
271271

‎src/client.ts‎

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -252,8 +252,6 @@ export class Pushy {
252252
throwIfEnabled = (e: Error) => this.reporter.throwIfEnabled(e);
253253
onError: Reporter['onError'] = (listener) => this.reporter.onError(listener);
254254
wasEmitted = (e: unknown): boolean => this.reporter.wasEmitted(e);
255-
private emitError: Reporter['emitError'] = (...args) =>
256-
this.reporter.emitError(...args);
257255
notifyAfterCheckUpdate: Reporter['notifyAfterCheckUpdate'] = (state) =>
258256
this.reporter.notifyAfterCheckUpdate(state);
259257

‎src/clientDownload.ts‎

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -177,9 +177,17 @@ export class Downloader {
177177
};
178178
// @ts-expect-error harmony not in existing platforms
179179
const isHarmony = Platform.OS === 'harmony';
180-
const progressSubscription = (
181-
isHarmony ? DeviceEventEmitter : pushyNativeEventEmitter
182-
).addListener('RCTPushyDownloadProgress', onNativeProgress);
180+
// Two separate calls: on RN 0.88 the two emitters' addListener signatures
181+
// no longer unify, so calling it on the union type does not compile.
182+
const progressSubscription = isHarmony
183+
? DeviceEventEmitter.addListener(
184+
'RCTPushyDownloadProgress',
185+
onNativeProgress
186+
)
187+
: pushyNativeEventEmitter.addListener(
188+
'RCTPushyDownloadProgress',
189+
onNativeProgress
190+
);
183191
const maxRetries = Math.max(
184192
0,
185193
Math.floor(this.host.options.maxRetries ?? 3)

‎tsconfig.build.json‎

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
{
2+
// Emits the published type declarations (lib/typescript), which
3+
// package.json `types` points at: apps then type-check against .d.ts files
4+
// their skipLibCheck covers, instead of compiling this package's sources
5+
// under their own tsconfig and React Native version.
6+
"extends": "./tsconfig.json",
7+
"include": ["src"],
8+
"exclude": ["src/__tests__"],
9+
"compilerOptions": {
10+
"noEmit": false,
11+
"declaration": true,
12+
"emitDeclarationOnly": true,
13+
"rootDir": "src",
14+
"outDir": "lib/typescript"
15+
}
16+
}

0 commit comments

Comments
 (0)