You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: apps/site/pages/en/learn/typescript/publishing.md
+176Lines changed: 176 additions & 0 deletions
Original file line number
Diff line number
Diff line change
@@ -5,3 +5,179 @@ authors: JakobJingleheimer
5
5
---
6
6
7
7
# Publishing a TypeScript package
8
+
9
+
This article augments TypeScript's [Publishing guide](https://www.typescriptlang.org/docs/handbook/declaration-files/publishing.html) with specifics for native node support.
10
+
11
+
Some important things to note:
12
+
13
+
- Node runs typescript via a process called "type stripping", wherein node (via SWC under the hood of [Amaro](https://github.com/nodejs/amaro)) removes TypeScript-specific syntax, leaving behind vanilla JavaScript (which node already understands). This behaviour is enabled by default of node version 23.6.0.
14
+
15
+
- Node does **not** strip types in `node_modules`. This decision was at the request of TypeScript maintainers because it can cause significant performance issues for the official compiler (`tsc`).
16
+
17
+
- TypeScript-specific features like `enum` still require a flag ([`--experimental-transform-types`](https://nodejs.org/api/typescript.html#typescript-features))
18
+
19
+
## What to do with your types
20
+
21
+
### Treat them like a test
22
+
23
+
The purpose of types are to warn an implementation will not work:
24
+
25
+
```ts
26
+
const foo ='a';
27
+
const bar:number=1+foo;
28
+
// ^^^ Type 'string' is not assignable to type 'number'.
29
+
```
30
+
31
+
TypeScript has warned you that the above code will not behave as intended, just like a unit test warns you code does not behave as intended.
32
+
33
+
Your IDE (ex VS Code) likely has built-in support for TypeScript, displaying errors as you work. If not, and/or you missed those, CI will have your back.
34
+
35
+
```yaml displayName=".github/workflows/ci.yml"
36
+
name: Tests
37
+
38
+
on:
39
+
push:
40
+
branches: ['main']
41
+
pull_request:
42
+
branches: ['main']
43
+
44
+
jobs:
45
+
lint-and-check-types:
46
+
# Separate these from tests because
47
+
# they are platform and node-version independent.
48
+
49
+
runs-on: ubuntu-latest
50
+
51
+
steps:
52
+
- uses: actions/checkout@v4
53
+
- uses: actions/setup-node@v4
54
+
with:
55
+
node-version-file: '.nvmrc'
56
+
cache: 'npm'
57
+
- name: npm clean install
58
+
run: npm ci
59
+
- run: node --run lint
60
+
- run: node --run types:check
61
+
62
+
test:
63
+
runs-on: ubuntu-latest
64
+
65
+
strategy:
66
+
matrix:
67
+
node:
68
+
- version: 23.x
69
+
- version: 22.x
70
+
# glob is not backported below 22.x
71
+
fail-fast: false # prevent a failure in one version cancelling other runs
72
+
73
+
steps:
74
+
- uses: actions/checkout@v4
75
+
- name: Use Node.js ${{ matrix.node.version }}
76
+
uses: actions/setup-node@v4
77
+
with:
78
+
node-version: ${{ matrix.node.version }}
79
+
cache: 'npm'
80
+
- name: npm clean install
81
+
run: npm ci
82
+
- run: node --run test
83
+
```
84
+
85
+
```json displayName="package.json"
86
+
{
87
+
"version": "0.0.0",
88
+
"name": "example-ts-pkg",
89
+
"scripts": {
90
+
"lint": "…",
91
+
"types:check": "tsc --noEmit"
92
+
},
93
+
"optionalDependencies": {
94
+
// This is used only in CI.
95
+
// Marking it 'optional' avoids installing on your local
96
+
// (where you probably won't use it).
97
+
"typescript": "^5.7.2"
98
+
}
99
+
}
100
+
```
101
+
102
+
```json displayName="tsconfig.json"
103
+
{
104
+
"compilerOptions": {
105
+
"declarationMap": true,
106
+
"declaration": true,
107
+
"emitDeclarationOnly": true,
108
+
"esModuleInterop": true, // Flux Capacitor: The universe breaks without it, but nobody knows what it does.
109
+
"module": "NodeNext",
110
+
"moduleResolution": "NodeNext",
111
+
"target": "ESNext"
112
+
},
113
+
// These may be different for your repo:
114
+
"include": "./src",
115
+
"exclude": ["**/*/*.test.*"]
116
+
}
117
+
```
118
+
119
+
### Generating type declarations
120
+
121
+
Type declarations (`.d.ts` and friends) provide type information as a sidecar file, allowing the execution code to be vanilla JavaScript whilst still having types.
122
+
123
+
Since these are generated based on source code, they can be built as part of your publication process and do not need to be checked into your repository.
124
+
125
+
Take the following example (a [GitHub Action](https://github.com/features/actions)), where the type declarations are generated just before publishing to the NPM registry.
# You can probably ignore the boilerplate config above
150
+
151
+
- name: Generate types
152
+
run: node --run types:generate
153
+
154
+
- name: Publish with provenance
155
+
env:
156
+
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
157
+
run: npm publish --access public --provenance
158
+
```
159
+
160
+
```diff displayName="package.json"
161
+
{
162
+
"name": "example-ts-pkg",
163
+
"scripts": {
164
+
"types:check": "tsc --noEmit",
165
+
+ "types:generate": "tsc"
166
+
}
167
+
}
168
+
```
169
+
170
+
```text displayName=".npmignore"
171
+
*.test.*
172
+
*.fixture.*
173
+
fixture.*
174
+
fixtures
175
+
```
176
+
177
+
#### Breaking this down
178
+
179
+
Generating type declarations is deterministic: you'll get the same output from the same input, every time. So there is no need to commit these to git.
180
+
181
+
[`npm publish`](https://docs.npmjs.com/cli/v11/commands/npm-publish) grabs everything applicable and available at the moment the command is run; so generating type declarations immediately before means those are available and will get picked up.
182
+
183
+
By default, `npm publish` grabs (almost) everything (see [Files included in package](https://docs.npmjs.com/cli/v11/commands/npm-publish#files-included-in-package)). In order to keep your published package minimal (see the "Heaviest Objects in the Universe" meme about `node_modules`), you want to exclude certain files (like tests and test fixtures) from from packaging.
0 commit comments