@mkappelhof/ts-config 1.0.5 → 2.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,13 @@
1
+
2
+ > @mkappelhof/ts-config@1.0.7 build /Users/mauricekappelhof/Dev/frontend-tools/packages/ts-config
3
+ > rollup -c
4
+
5
+ 
6
+ ./base.json → ./dist/base.json...
7
+ (!) Mixing named and default exports
8
+ https://rollupjs.org/configuration-options/#output-exports
9
+ The following entry modules are using named and default exports together:
10
+ base.json
11
+
12
+ Consumers of your bundle will have to use chunk.default to access their default export, which may not be what you want. Use `output.exports: "named"` to disable this warning.
13
+ created ./dist/base.json in 22ms
package/AGENTS.md ADDED
@@ -0,0 +1,61 @@
1
+ # @mkappelhof/ts-config — agent instructions
2
+
3
+ This project's `tsconfig.json` extends a shared config from `@mkappelhof/ts-config`. Write code that type-checks under these settings, and do not loosen them.
4
+
5
+ ## Which config is in use
6
+
7
+ Check `extends` in the project's `tsconfig.json`:
8
+
9
+ | Config | For | Module system |
10
+ | --- | --- | --- |
11
+ | `@mkappelhof/ts-config/next.json` | Next.js apps | ESM, bundler resolution, type-check only (`noEmit`) |
12
+ | `@mkappelhof/ts-config/react.json` | React apps and libraries built with a bundler (Vite, etc.) | ESM, bundler resolution, type-check only (`noEmit`) |
13
+ | `@mkappelhof/ts-config/node.json` | Node.js 24+ services, scripts and CLIs | Native Node ESM (`NodeNext`) |
14
+ | `@mkappelhof/ts-config/library.json` | React libraries built with a bundler that publish type declarations | ESM, bundler resolution, declaration emit only (`emitDeclarationOnly`) |
15
+ | `@mkappelhof/ts-config/astro.json` | Astro sites and apps | ESM, bundler resolution, type-check only (`noEmit`), `jsx: "preserve"` |
16
+
17
+ ## Rules that apply to every config
18
+
19
+ - **`strict` is on, plus `noUncheckedIndexedAccess`.** Indexing an array or record returns `T | undefined`. Narrow it (`if (item)`, `?.`, `??`) instead of using `!` or `as`.
20
+ - **`noImplicitOverride`.** Mark overridden class members with `override`.
21
+ - **`noFallthroughCasesInSwitch`.** Every non-empty `case` must `break`, `return` or `throw`.
22
+ - Path aliases are defined in `compilerOptions.paths` in the project's own `tsconfig.json`, never in these presets. Check there before assuming an import needs a relative path.
23
+ - Ambient types beyond the preset's `lib` (e.g. `chrome` for a browser extension, or a test runner's globals) go in `compilerOptions.types` in the project's own `tsconfig.json`.
24
+ - Do not add `// @ts-ignore`. If you must suppress an error, use `// @ts-expect-error` with a reason.
25
+ - Do not change the compiler options in the project's `tsconfig.json` to make an error go away. Fix the code.
26
+
27
+ ## next.json
28
+
29
+ - JSX uses the automatic runtime (`react-jsx`). Do not `import React` just for JSX.
30
+ - Imports have no file extensions (`import { x } from './util'`).
31
+ - Keep `next-env.d.ts` and the `.next/types/**/*.ts` entries in `include`. Next.js generates them.
32
+ - Run `pnpm tsc --noEmit` (or `pnpm next build`) to type-check.
33
+
34
+ ## react.json
35
+
36
+ - `verbatimModuleSyntax` is on. Import types with `import type { Foo } from './foo'` (or the inline form `import { type Foo }`).
37
+ - `erasableSyntaxOnly` is on. Do not use `enum`, `namespace`, parameter properties (`constructor(private x: string)`) or `import x = require()`. Use union types or `as const` objects instead of enums.
38
+ - JSX uses the automatic runtime (`react-jsx`). Do not `import React` just for JSX.
39
+ - `.ts` / `.tsx` extensions in imports are allowed but not required.
40
+
41
+ ## library.json
42
+
43
+ - Extends `react.json`, so the same `verbatimModuleSyntax` and `erasableSyntaxOnly` rules apply.
44
+ - `noEmit` is off and `emitDeclarationOnly` is on: `tsc` only ever emits `.d.ts` files, never `.js`. Build the JS with your bundler, and run `tsc` (or `tsc --build`) separately to emit declarations.
45
+ - Set `outDir` and `rootDir` in the project's own `tsconfig.json`.
46
+
47
+ ## node.json
48
+
49
+ - The project must have `"type": "module"` in `package.json`. Use `import`/`export` and never `require`/`module.exports`.
50
+ - **Relative imports must include the file extension.** Write `import { x } from './util.ts'` (or `./util.js`). Both resolve, and `.ts` is rewritten to `.js` on emit.
51
+ - `verbatimModuleSyntax` and `erasableSyntaxOnly` are on, same rules as `react.json`. Because of the latter, the source can run directly with `node file.ts`.
52
+ - Top-level `await` is allowed.
53
+ - `@types/node` must be installed. It is the only ambient types package loaded (`"types": ["node"]`); add others to `types` in the project's `tsconfig.json`.
54
+
55
+ ## astro.json
56
+
57
+ - `jsx` is `"preserve"`, not `"react-jsx"`. `.astro` files are their own syntax, compiled by the Astro compiler, not `tsc`; this setting only matters for `.tsx` islands (e.g. from `@astrojs/react`), and Astro's Vite plugin handles their actual JSX transform regardless of this setting.
58
+ - `verbatimModuleSyntax` and `erasableSyntaxOnly` are on, same rules as `react.json`/`node.json`: use `import type`, and no `enum`, `namespace` or parameter properties.
59
+ - Ambient types for `astro:*` virtual modules and `import.meta.env` come from `/// <reference types="astro/client" />` in your own code (commonly in `src/env.d.ts`), not from this preset.
60
+ - This preset does not `extend` Astro's own `astro/tsconfigs/strict.json` — it's self-contained, with the equivalent compiler options plus this package's usual `noUncheckedIndexedAccess`, `noImplicitOverride` and `noFallthroughCasesInSwitch` (Astro's `strict.json` alone does not enable these three; `strictest.json` does, but also turns on other checks this package doesn't standardize on, such as `noUnusedLocals`).
61
+ - Use `astro check` to type-check, not bare `tsc --noEmit` — only the Astro CLI resolves `.astro` files.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,57 @@
1
1
  # @mkappelhof/ts-config
2
2
 
3
+ ## 2.0.1
4
+
5
+ ### Patch Changes
6
+
7
+ - eb2577f: Add new configs
8
+
9
+ ## 2.0.0
10
+
11
+ ### Major Changes
12
+
13
+ - 9665a73: Modernise `next.json`, `react.json` and `node.json` for TypeScript 6/7, Next.js 16 and Node 24. They no longer extend `base.json`; use `bundler`/`NodeNext` module resolution; and enable `noUncheckedIndexedAccess`. `react.json` and `node.json` also enable `verbatimModuleSyntax` and `erasableSyntaxOnly`, and `node.json` targets native ESM. Adds `AGENTS.md`.
14
+
15
+ Also:
16
+
17
+ - Adds a `library.json` preset (extends `react.json`) for React libraries that publish type declarations, replacing the manual `compilerOptions` override documented in the README.
18
+ - Removes the Rollup build. `main` already pointed at the source `base.json`, and nothing consumed the `dist/` output it produced.
19
+
20
+ ### Minor Changes
21
+
22
+ - 1eb73de: Add an `astro.json` preset to `@mkappelhof/ts-config`, pulled from how a real Astro site configures
23
+ TypeScript: Astro's own `strict.json` base plus this package's usual `noUncheckedIndexedAccess`,
24
+ `noImplicitOverride` and `noFallthroughCasesInSwitch`.
25
+
26
+ Also documents pinning Biome's `astro` lint domain in `@mkappelhof/biome-config`'s README, alongside
27
+ the existing `react`/`next`/`test` domain guidance.
28
+
29
+ ### Patch Changes
30
+
31
+ - 58ff254: Pull in live configuration learnings from a real project:
32
+
33
+ - `@mkappelhof/biome-config`: enable `html.experimentalFullSupportEnabled`, and document in the
34
+ `AGENTS.md`/README how to pair this config with `@mkappelhof/stylelint-config` without the two
35
+ tools overlapping on the same files.
36
+ - `@mkappelhof/ts-config`: document in `AGENTS.md` that `react.json` projects define path aliases
37
+ and any extra ambient `types` (e.g. browser-extension globals) in their own `tsconfig.json`.
38
+
39
+ Also adds a new `@mkappelhof/stylelint-config` package (Stylelint config for CSS/SCSS, built on
40
+ `stylelint-config-standard` + `stylelint-config-recommended-scss`), for projects that pair Biome
41
+ with Stylelint instead of relying on Biome for styles.
42
+
43
+ ## 1.0.7
44
+
45
+ ### Patch Changes
46
+
47
+ - 7a413a3: Add deployment to Github
48
+
49
+ ## 1.0.6
50
+
51
+ ### Patch Changes
52
+
53
+ - 0e9c110: Add Remix config
54
+
3
55
  ## 1.0.5
4
56
 
5
57
  ### Patch Changes
package/README.md CHANGED
@@ -1,15 +1,126 @@
1
- # Shared Typescript configurations
1
+ # Shared TypeScript configurations
2
+
3
+ Shared `tsconfig.json` presets for TypeScript 6 and 7.
4
+
5
+ | Config | Use for |
6
+ | --- | --- |
7
+ | `@mkappelhof/ts-config/next.json` | Next.js applications |
8
+ | `@mkappelhof/ts-config/react.json` | React apps and libraries built with a bundler (Vite, Rsbuild, etc.) |
9
+ | `@mkappelhof/ts-config/node.json` | Node.js 24+ services, scripts and CLIs (native ESM) |
10
+ | `@mkappelhof/ts-config/library.json` | React libraries built with a bundler that publish type declarations |
11
+ | `@mkappelhof/ts-config/astro.json` | Astro sites and apps |
12
+
13
+ All presets enable `strict`, `noUncheckedIndexedAccess`, `noImplicitOverride` and `noFallthroughCasesInSwitch`.
2
14
 
3
15
  ## Installation
4
16
 
5
- Add the package as a local dev dependency
17
+ ```sh
18
+ pnpm add -D @mkappelhof/ts-config typescript
19
+ ```
6
20
 
7
- `yarn add @mkappelhof/ts-config`
21
+ Paths in `include`, `exclude`, `paths` and `outDir` are resolved relative to the config file that declares them. That's why the presets don't set them, and your own `tsconfig.json` has to.
8
22
 
9
- Then create a `.tsconfig.json` config file with the following content:
23
+ ### Next.js
10
24
 
11
25
  ```JSON
12
26
  {
13
27
  "extends": "@mkappelhof/ts-config/next.json",
28
+ "compilerOptions": {
29
+ "paths": { "@/*": ["./src/*"] }
30
+ },
31
+ "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", "**/*.mts", ".next/types/**/*.ts", ".next/dev/types/**/*.ts"],
32
+ "exclude": ["node_modules"]
33
+ }
34
+ ```
35
+
36
+ ### React (bundler)
37
+
38
+ ```sh
39
+ pnpm add -D @types/react @types/react-dom
40
+ ```
41
+
42
+ ```JSON
43
+ {
44
+ "extends": "@mkappelhof/ts-config/react.json",
45
+ "compilerOptions": {
46
+ "types": ["vite/client"]
47
+ },
48
+ "include": ["src"]
49
+ }
50
+ ```
51
+
52
+ The preset is type-check only (`noEmit`). For a React library that publishes type declarations, use `library.json` instead:
53
+
54
+ ```JSON
55
+ {
56
+ "extends": "@mkappelhof/ts-config/library.json",
57
+ "compilerOptions": {
58
+ "outDir": "dist",
59
+ "rootDir": "src"
60
+ },
61
+ "include": ["src"]
62
+ }
63
+ ```
64
+
65
+ ### Node.js
66
+
67
+ ```sh
68
+ pnpm add -D @types/node
69
+ ```
70
+
71
+ Set `"type": "module"` in your `package.json`, then:
72
+
73
+ ```JSON
74
+ {
75
+ "extends": "@mkappelhof/ts-config/node.json",
76
+ "compilerOptions": {
77
+ "outDir": "dist",
78
+ "rootDir": "src"
79
+ },
80
+ "include": ["src"]
81
+ }
82
+ ```
83
+
84
+ The code only uses erasable TypeScript syntax, so you can run it directly with `node src/index.ts` or compile it with `tsc`. Relative imports must include an extension (`./util.ts`), which is rewritten to `.js` on emit.
85
+
86
+ ### Astro
87
+
88
+ ```JSON
89
+ {
90
+ "extends": "@mkappelhof/ts-config/astro.json",
91
+ "compilerOptions": {
92
+ "paths": { "@components/*": ["./src/components/*"] }
93
+ },
94
+ "include": [".astro/types.d.ts", "src"],
95
+ "exclude": ["dist"]
14
96
  }
15
97
  ```
98
+
99
+ This preset is self-contained (it doesn't `extend` Astro's own `astro/tsconfigs/*` presets), but
100
+ applies the same strictness as the rest of this package on top of what Astro's `strict.json`
101
+ enables: `noUncheckedIndexedAccess`, `noImplicitOverride` and `noFallthroughCasesInSwitch`. Type
102
+ declarations for `astro:*` virtual modules and `import.meta.env` come from a triple-slash
103
+ reference in your own code, not from this preset:
104
+
105
+ ```ts
106
+ /// <reference types="astro/client" />
107
+ ```
108
+
109
+ Run `astro check` to type-check (plain `tsc --noEmit` won't resolve `.astro` files).
110
+
111
+ ## Breaking changes in 2.0
112
+
113
+ - `next.json`, `react.json` and `node.json` no longer extend `base.json`.
114
+ - `moduleResolution` is now `bundler` (Next.js, React) or `NodeNext` (Node), instead of the removed `node10`.
115
+ - `node.json` now targets Node 24 ESM instead of CommonJS.
116
+ - `react.json` and `node.json` enable `verbatimModuleSyntax` and `erasableSyntaxOnly`. Use `import type` for type-only imports, and replace `enum`s with union types or `as const` objects.
117
+ - `noUncheckedIndexedAccess` is on in every preset.
118
+ - In `next.json`, the `next` plugin moved into `compilerOptions`, where TypeScript actually reads it.
119
+
120
+ ## AI agents
121
+
122
+ The package ships an `AGENTS.md` that explains the rules these presets enforce. Reference it from your project's `AGENTS.md`:
123
+
124
+ ```md
125
+ - TypeScript: follow `node_modules/@mkappelhof/ts-config/AGENTS.md`
126
+ ```
package/astro.json ADDED
@@ -0,0 +1,30 @@
1
+ {
2
+ "$schema": "https://www.schemastore.org/tsconfig",
3
+ "display": "Astro",
4
+ "compilerOptions": {
5
+ "target": "ESNext",
6
+ "lib": [
7
+ "DOM",
8
+ "DOM.Iterable",
9
+ "ESNext"
10
+ ],
11
+ "module": "ESNext",
12
+ "moduleResolution": "bundler",
13
+ "moduleDetection": "force",
14
+ "jsx": "preserve",
15
+ "allowJs": true,
16
+ "allowImportingTsExtensions": true,
17
+ "resolveJsonModule": true,
18
+ "verbatimModuleSyntax": true,
19
+ "isolatedModules": true,
20
+ "erasableSyntaxOnly": true,
21
+ "noEmit": true,
22
+ "strict": true,
23
+ "noUncheckedIndexedAccess": true,
24
+ "noImplicitOverride": true,
25
+ "noFallthroughCasesInSwitch": true,
26
+ "forceConsistentCasingInFileNames": true,
27
+ "esModuleInterop": true,
28
+ "skipLibCheck": true
29
+ }
30
+ }
package/base.json CHANGED
@@ -19,5 +19,7 @@
19
19
  "skipLibCheck": true,
20
20
  "strict": true
21
21
  },
22
- "exclude": ["node_modules"]
23
- }
22
+ "exclude": [
23
+ "node_modules"
24
+ ]
25
+ }
package/library.json ADDED
@@ -0,0 +1,12 @@
1
+ {
2
+ "$schema": "https://www.schemastore.org/tsconfig",
3
+ "display": "React Library",
4
+ "extends": "./react.json",
5
+ "compilerOptions": {
6
+ "noEmit": false,
7
+ "declaration": true,
8
+ "declarationMap": true,
9
+ "emitDeclarationOnly": true,
10
+ "allowImportingTsExtensions": false
11
+ }
12
+ }
package/next.json CHANGED
@@ -1,17 +1,31 @@
1
1
  {
2
- "$schema": "https://json.schemastore.org/tsconfig",
3
- "display": "React Library",
4
- "extends": "./base.json",
2
+ "$schema": "https://www.schemastore.org/tsconfig",
3
+ "display": "Next.js",
5
4
  "compilerOptions": {
6
- "incremental": true,
7
- "jsx": "preserve",
8
- "lib": ["dom", "ES2015"],
5
+ "target": "ES2022",
6
+ "lib": [
7
+ "DOM",
8
+ "DOM.Iterable",
9
+ "ESNext"
10
+ ],
9
11
  "module": "ESNext",
10
- "target": "es6"
11
- },
12
- "plugins": [
13
- {
14
- "name": "next"
15
- }
16
- ]
17
- }
12
+ "moduleResolution": "bundler",
13
+ "moduleDetection": "force",
14
+ "jsx": "react-jsx",
15
+ "allowJs": true,
16
+ "resolveJsonModule": true,
17
+ "isolatedModules": true,
18
+ "noEmit": true,
19
+ "incremental": true,
20
+ "strict": true,
21
+ "noUncheckedIndexedAccess": true,
22
+ "noImplicitOverride": true,
23
+ "noFallthroughCasesInSwitch": true,
24
+ "skipLibCheck": true,
25
+ "plugins": [
26
+ {
27
+ "name": "next"
28
+ }
29
+ ]
30
+ }
31
+ }
package/node.json CHANGED
@@ -1,10 +1,29 @@
1
1
  {
2
- "$schema": "https://json.schemastore.org/tsconfig",
3
- "display": "Node 18",
4
- "extends": "./base.json",
2
+ "$schema": "https://www.schemastore.org/tsconfig",
3
+ "display": "Node 24",
5
4
  "compilerOptions": {
6
- "lib": ["ES2020"],
7
- "module": "commonjs",
8
- "target": "ES2020"
5
+ "target": "ES2024",
6
+ "lib": [
7
+ "ES2024",
8
+ "ESNext.Array",
9
+ "ESNext.Collection",
10
+ "ESNext.Iterator",
11
+ "ESNext.Promise"
12
+ ],
13
+ "module": "NodeNext",
14
+ "moduleResolution": "NodeNext",
15
+ "moduleDetection": "force",
16
+ "types": [
17
+ "node"
18
+ ],
19
+ "resolveJsonModule": true,
20
+ "verbatimModuleSyntax": true,
21
+ "erasableSyntaxOnly": true,
22
+ "rewriteRelativeImportExtensions": true,
23
+ "strict": true,
24
+ "noUncheckedIndexedAccess": true,
25
+ "noImplicitOverride": true,
26
+ "noFallthroughCasesInSwitch": true,
27
+ "skipLibCheck": true
9
28
  }
10
29
  }
package/package.json CHANGED
@@ -1,23 +1,19 @@
1
1
  {
2
2
  "name": "@mkappelhof/ts-config",
3
- "version": "1.0.5",
3
+ "version": "2.0.1",
4
4
  "main": "base.json",
5
5
  "license": "MIT",
6
6
  "repository": "git@github.com:mkappelhof/frontend-tools.git",
7
7
  "author": "Maurice Kappelhof <maurice@mauricekappelhof.nl>",
8
8
  "scripts": {
9
- "build": "rollup -c",
10
9
  "test": "echo 'No test step'"
11
10
  },
12
11
  "peerDependencies": {
13
- "typescript": "5.1.6"
14
- },
15
- "devDependencies": {
16
- "@rollup/plugin-json": "6.0.0"
12
+ "typescript": "^6.0.0 || ^7.0.0"
17
13
  },
18
14
  "tags": [
19
15
  "typescript",
20
16
  "tsconfig",
21
17
  "config"
22
18
  ]
23
- }
19
+ }
package/react.json CHANGED
@@ -1,11 +1,26 @@
1
1
  {
2
- "$schema": "https://json.schemastore.org/tsconfig",
3
- "display": "React Library",
4
- "extends": "./base.json",
2
+ "$schema": "https://www.schemastore.org/tsconfig",
3
+ "display": "React",
5
4
  "compilerOptions": {
6
- "jsx": "react-jsx",
7
- "lib": ["dom", "ES2015"],
5
+ "target": "ES2023",
6
+ "lib": [
7
+ "DOM",
8
+ "DOM.Iterable",
9
+ "ES2023"
10
+ ],
8
11
  "module": "ESNext",
9
- "target": "es6"
12
+ "moduleResolution": "bundler",
13
+ "moduleDetection": "force",
14
+ "jsx": "react-jsx",
15
+ "allowImportingTsExtensions": true,
16
+ "resolveJsonModule": true,
17
+ "verbatimModuleSyntax": true,
18
+ "erasableSyntaxOnly": true,
19
+ "noEmit": true,
20
+ "strict": true,
21
+ "noUncheckedIndexedAccess": true,
22
+ "noImplicitOverride": true,
23
+ "noFallthroughCasesInSwitch": true,
24
+ "skipLibCheck": true
10
25
  }
11
- }
26
+ }
package/remix.json ADDED
@@ -0,0 +1,16 @@
1
+ {
2
+ "$schema": "https://json.schemastore.org/tsconfig",
3
+ "display": "Remix",
4
+ "extends": "./base.json",
5
+ "compilerOptions": {
6
+ "lib": [
7
+ "DOM",
8
+ "DOM.Iterable",
9
+ "ESNext"
10
+ ],
11
+ "jsx": "react-jsx",
12
+ "moduleResolution": "node",
13
+ "target": "ESNext",
14
+ "baseUrl": "."
15
+ }
16
+ }
package/rollup.config.js DELETED
@@ -1,22 +0,0 @@
1
- const copy = require("rollup-plugin-copy");
2
- const json = require("@rollup/plugin-json");
3
-
4
- module.exports = {
5
- input: "./base.json",
6
- output: {
7
- file: "./dist/base.json",
8
- format: "cjs",
9
- },
10
- plugins: [
11
- json(),
12
- copy({
13
- targets: [
14
- { src: "./next.json", dest: "./dist/" },
15
- { src: "./node.json", dest: "./dist/" },
16
- { src: "./react.json", dest: "./dist/" },
17
- { src: "./CHANGELOG.md", dest: "./dist/" },
18
- { src: "./package.json", dest: "./dist/" },
19
- ],
20
- }),
21
- ],
22
- };