|
1 | 1 | # TypeScript Plugin Support |
2 | 2 |
|
3 | | -Use the [`@knighted/jsx-ts-plugin`](https://github.com/knightedcodemonkey/jsx-ts-plugin) to teach both the TypeScript language service and `tsc --noEmit` how to interpret `@knighted/jsx` tagged templates. The plugin understands the DOM (`jsx`) and React (`reactJsx`) entrypoints, applies mode-aware diagnostics, and forwards the same rules to the compiler so command-line builds match what your editor reports. |
| 3 | +Use the [`@knighted/jsx-ts-plugin`](https://github.com/knightedcodemonkey/jsx-ts-plugin) to teach the TypeScript language service how to interpret `@knighted/jsx` tagged templates. The plugin understands the DOM (`jsx`) and React (`reactJsx`) entrypoints and applies mode-aware diagnostics so editors surface real JSX errors inside template literals. |
| 4 | + |
| 5 | +> [!IMPORTANT] |
| 6 | +> TypeScript only loads language-service plugins inside editors (via `tsserver`). Running `tsc` or `tsc --noEmit` directly will **not** execute this plugin. To enforce the same diagnostics in CI, pair your build with a compiler transform (loader, `ts-patch`, etc.) or run a custom check that reuses the plugin’s transformation logic. |
4 | 7 |
|
5 | 8 | ## Installation |
6 | 9 |
|
@@ -37,7 +40,8 @@ Restart your editor after saving the config. From VS Code you can run **TypeScri |
37 | 40 |
|
38 | 41 | - `jsx` templates run in **DOM mode** (accepting DOM nodes, strings, iterables, etc.). |
39 | 42 | - `reactJsx` templates run in **React mode** (accepting `ReactNode`, hooks, and JSX component types). |
40 | | -- `tsc --noEmit` and `tsserver` share the same diagnostics, so CI sees the exact errors you see inside your editor. |
| 43 | + |
| 44 | +Editors surface the extra diagnostics immediately because the plugin runs inside `tsserver`. Command-line builds still rely on whichever compiler transform or loader you configure outside this plugin. |
41 | 45 |
|
42 | 46 | You can override the mode per expression by dropping an inline directive immediately before the template literal: |
43 | 47 |
|
@@ -65,11 +69,48 @@ const view = jsx`<span>${asRenderable(payload)}</span>` |
65 | 69 |
|
66 | 70 | React mode continues to rely on `ReactNode`, so projects that import both helpers can keep using the standard React types. |
67 | 71 |
|
| 72 | +### DOM component example |
| 73 | + |
| 74 | +When you build DOM-only helpers (like badges rendered into Lit components), type them with `JsxRenderable` so you never have to cast to `ReactNode`: |
| 75 | + |
| 76 | +```ts |
| 77 | +import { jsx } from '@knighted/jsx' |
| 78 | +import type { JsxRenderable } from '@knighted/jsx' |
| 79 | + |
| 80 | +type DomBadgeProps = { label: JsxRenderable } |
| 81 | + |
| 82 | +export const DomBadge = ({ label }: DomBadgeProps): HTMLElement => { |
| 83 | + let clicks = 0 |
| 84 | + const counterText = jsx`<span>Clicked ${clicks} times</span>` as HTMLSpanElement |
| 85 | + |
| 86 | + return jsx` |
| 87 | + <article class="dom-badge"> |
| 88 | + <header> |
| 89 | + <h2>Lit + DOM with jsx</h2> |
| 90 | + <p data-kind="react">${label}</p> |
| 91 | + </header> |
| 92 | + <button |
| 93 | + type="button" |
| 94 | + data-kind="dom-counter" |
| 95 | + onClick=${() => { |
| 96 | + clicks += 1 |
| 97 | + counterText.textContent = `Clicked ${clicks} times` |
| 98 | + }} |
| 99 | + > |
| 100 | + ${counterText} |
| 101 | + </button> |
| 102 | + </article> |
| 103 | + ` as HTMLDivElement |
| 104 | +} |
| 105 | +``` |
| 106 | + |
| 107 | +Here `label` stays fully typed as a DOM-friendly value, and the component returns an `HTMLElement`, so nothing needs to be widened to `ReactNode`. |
| 108 | + |
68 | 109 | ## Editor checklist |
69 | 110 |
|
70 | 111 | 1. Install `@knighted/jsx-ts-plugin` as a dev dependency. |
71 | 112 | 2. Add a single plugin block in `tsconfig.json` (as shown above) or extend it with additional `tagModes` for custom tags. |
72 | 113 | 3. Restart your editor and point VS Code at the workspace TypeScript version so the plugin loads. |
73 | | -4. Run `tsc --noEmit` in CI to surface the same diagnostics the editor shows. |
| 114 | +4. Pair your CI/build step with the loader or compiler transform you already use for `@knighted/jsx` templates—`tsc --noEmit` alone will not load the language-service plugin. |
74 | 115 |
|
75 | 116 | Following the checklist keeps DOM and React templates aligned across the entire toolchain—no ReactNode casts, no mismatched compiler results, and no duplicate plugin entries. |
0 commit comments