@elliots/typical 0.2.5 → 0.3.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.
Files changed (2) hide show
  1. package/README.md +70 -8
  2. package/package.json +12 -3
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Typical
2
2
 
3
- Typical makes TypeScript type-safe at runtime _with no changes to your code_.
3
+ Typical makes TypeScript type safe at runtime _with no changes to your code_.
4
4
 
5
5
  It transforms your code to inject runtime validation based on your existing type annotations. With source maps, so errors point to the right lines in your original code.
6
6
 
@@ -38,13 +38,14 @@ const user = JSON.parse('{"name":"Alice","email":"not-an-email"}') as User;
38
38
 
39
39
  Choose the integration that fits your workflow:
40
40
 
41
- | Method | Best For | Package |
42
- | --------------------------------------------------------- | ------------------------------- | ----------------------------- |
43
- | [ESM Loader](#nodejs-esm-loader) | Node.js scripts, development | `@elliots/typical` |
44
- | [ttsx](#ttsx-tsx-wrapper) | Quick scripts with tsx | `@elliots/typical` + `tsx` |
45
- | [Bun Plugin](#bun) | Bun projects | `@elliots/bun-plugin-typical` |
46
- | [Vite/Webpack/etc](#bundlers-vite-webpack-rollup-esbuild) | Frontend apps, bundled projects | `@elliots/unplugin-typical` |
47
- | [tsc Plugin](#typescript-compiler-tsc) | Pure TypeScript compilation | `@elliots/typical-tsc-plugin` |
41
+ | Method | Best For | Package |
42
+ | --------------------------------------------------------- | ------------------------------- | ------------------------------------ |
43
+ | [ESM Loader](#nodejs-esm-loader) | Node.js scripts, development | `@elliots/typical` |
44
+ | [ttsx](#ttsx-tsx-wrapper) | Quick scripts with tsx | `@elliots/typical` + `tsx` |
45
+ | [Bun Plugin](#bun) | Bun projects | `@elliots/bun-plugin-typical` |
46
+ | [React Native / Expo](#react-native--expo) | React Native apps | `@elliots/metro-transformer-typical` |
47
+ | [Vite/Webpack/etc](#bundlers-vite-webpack-rollup-esbuild) | Frontend apps, bundled projects | `@elliots/unplugin-typical` |
48
+ | [tsc Plugin](#typescript-compiler-tsc) | Pure TypeScript compilation | `@elliots/typical-tsc-plugin` |
48
49
 
49
50
  ---
50
51
 
@@ -123,6 +124,44 @@ bun run src/index.ts
123
124
 
124
125
  ---
125
126
 
127
+ ## React Native / Expo
128
+
129
+ ```bash
130
+ npm add @elliots/metro-transformer-typical
131
+ ```
132
+
133
+ Update your `metro.config.js`:
134
+
135
+ ```js
136
+ // metro.config.js
137
+ const { getDefaultConfig } = require("expo/metro-config");
138
+ const { withTypical } = require("@elliots/metro-transformer-typical");
139
+
140
+ module.exports = withTypical(getDefaultConfig(__dirname));
141
+ ```
142
+
143
+ For vanilla React Native (without Expo):
144
+
145
+ ```js
146
+ // metro.config.js
147
+ const { getDefaultConfig } = require("@react-native/metro-config");
148
+ const { withTypical } = require("@elliots/metro-transformer-typical");
149
+
150
+ module.exports = withTypical(getDefaultConfig(__dirname));
151
+ ```
152
+
153
+ With options:
154
+
155
+ ```js
156
+ module.exports = withTypical(getDefaultConfig(__dirname), {
157
+ typical: {
158
+ validateCasts: true,
159
+ },
160
+ });
161
+ ```
162
+
163
+ ---
164
+
126
165
  ## Bundlers (Vite, Webpack, Rollup, esbuild)
127
166
 
128
167
  ```bash
@@ -352,6 +391,10 @@ The generated validation code is optimised for runtime performance:
352
391
 
353
392
  - **Reusable validators** - When the same type is validated multiple times, Typical hoists the validation logic to a reusable function at module scope. Nested types that appear in multiple places (e.g., `Address` used in both `User` and `Company`) are also extracted and reused.
354
393
  - **Smart redundancy elimination** - Skips validation when returning values that are already known to be valid: validated parameters, properties of validated objects, variables assigned from casts or `JSON.parse`, and aliased variables
394
+ - **Cross-file call graph analysis** - Analyses the entire project to eliminate redundant validation across files:
395
+ - **Trusted return values** - If a function validates its return type, callers don't re-validate the result
396
+ - **Internal function parameters** - Non-exported functions only called with pre-validated arguments skip parameter validation
397
+ - **Chained function calls** - When `step2(step1(user))` is called, validation flows through the chain
355
398
  - **Type-aware dirty tracking** - Tracks when validated values might become invalid. Primitives stay valid after being passed to functions (they're copied), but objects are re-validated if passed to unknown functions. Pure functions (listed in the config) like `console.log` don't invalidate objects.
356
399
  - **Union early bail-out** - Union type checks use if-else chains so the first matching type succeeds immediately
357
400
  - **Skip comments** - Add `// @typical-ignore` before a function to skip all validation for it
@@ -478,3 +521,22 @@ Runtime validation performance comparing Typical vs Zod vs no validation:
478
521
 
479
522
  - **vs Nothing**: Speed relative to no validation or filtering (1.0x = same speed)
480
523
  - **vs Zod**: Speed relative to Zod (1.0x = same speed)
524
+
525
+ ---
526
+
527
+ ## Changelog
528
+
529
+ <!-- CHANGELOG_START -->
530
+
531
+ ### v0.3.1 (2026-02-23)
532
+
533
+ Add metro transformer (React Native/Expo)
534
+
535
+ ### v0.3.0 (2026-01-14)
536
+
537
+ - Build call graph across whole project to avoid validating already-validated data
538
+ - Source map vis in the playround
539
+ - Add 'never' support, the property must not exist
540
+ - Fix: Node 24
541
+
542
+ <!-- CHANGELOG_END -->
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@elliots/typical",
3
- "version": "0.2.5",
3
+ "version": "0.3.1",
4
4
  "description": "Runtime safe TypeScript transformer using typia",
5
5
  "keywords": [
6
6
  "runtime",
@@ -40,19 +40,27 @@
40
40
  },
41
41
  "dependencies": {
42
42
  "commander": "14.0.2",
43
- "@elliots/typical-compiler": "0.2.5"
43
+ "@elliots/typical-compiler": "0.3.1"
44
44
  },
45
45
  "devDependencies": {
46
46
  "@types/node": "22",
47
47
  "c8": "10.1.3",
48
+ "nano-staged": "^0.9.0",
48
49
  "oxfmt": "^0.21.0",
49
50
  "oxlint": "1.36.0",
50
51
  "oxlint-tsgolint": "0.10.1",
52
+ "simple-git-hooks": "^2.13.1",
51
53
  "typescript": "5.9.3"
52
54
  },
53
55
  "peerDependencies": {
54
56
  "typescript": "^5.0.0"
55
57
  },
58
+ "simple-git-hooks": {
59
+ "pre-commit": "pnpm nano-staged"
60
+ },
61
+ "nano-staged": {
62
+ "*.{js,ts,tsx,jsx,json,md,html,css}": "oxfmt"
63
+ },
56
64
  "engines": {
57
65
  "pnpm": ">=10"
58
66
  },
@@ -67,7 +75,7 @@
67
75
  "build:ts": "pnpm --filter './packages/*' run build && tsc",
68
76
  "build:website": "pnpm --filter typical-website run build",
69
77
  "dev": "tsc --watch",
70
- "test": "rm -f test/test.temp.ts && tsc && node --import ./dist/src/esm-loader-register.js --test dist/test/*.test.js",
78
+ "test": "rm -f test/test.temp.ts && rm -rf test/project-fixtures && tsc && node --import ./dist/src/esm-loader-register.js --test dist/test/*.test.js",
71
79
  "test:coverage": "rm -f test/test.temp.ts && tsc && node --import ./dist/src/esm-loader-register.js --test --experimental-test-coverage dist/test/*.test.js",
72
80
  "test:coverage:html": "rm -f test/test.temp.ts && tsc && c8 --reporter=html --reporter=text --include='dist/src/**' node --import ./dist/src/esm-loader-register.js --test dist/test/*.test.js",
73
81
  "bench": "pnpm run build && cd bench && pnpm install && npm run bench",
@@ -78,6 +86,7 @@
78
86
  "sample:ttsc": "cd samples/ttsc && pnpm install && npm run build && npm run start",
79
87
  "sample:vite-react": "cd samples/vite-react && pnpm install && pnpm run test",
80
88
  "sample:bun": "cd samples/bun && pnpm install && bun run start",
89
+ "sample:react-native": "cd samples/react-native && pnpm install && npm run web",
81
90
  "samples": "npm run sample:esm && npm run sample:ttsx && npm run sample:vite-react && npm run sample:bun",
82
91
  "publish:all": "npm run lint && npm run format:check && node scripts/publish.js"
83
92
  }