rasti 4.1.3 → 4.1.4
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.
- package/README.md +21 -15
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<p align="center">
|
|
2
2
|
<picture>
|
|
3
|
-
<source media="(prefers-color-scheme: dark)" srcset="https://cdn.jsdelivr.net/gh/8tentaculos/rasti@v4.1.
|
|
4
|
-
<img alt="Rasti.js" src="https://cdn.jsdelivr.net/gh/8tentaculos/rasti@v4.1.
|
|
3
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://cdn.jsdelivr.net/gh/8tentaculos/rasti@v4.1.4/docs/logo-dark.svg">
|
|
4
|
+
<img alt="Rasti.js" src="https://cdn.jsdelivr.net/gh/8tentaculos/rasti@v4.1.4/docs/logo.svg" height="120">
|
|
5
5
|
</picture>
|
|
6
6
|
</p>
|
|
7
7
|
|
|
@@ -253,13 +253,13 @@ type CardComponent = Component<CardProps>;
|
|
|
253
253
|
|
|
254
254
|
const Card = Component.create<CardProps>`
|
|
255
255
|
<div class="card">
|
|
256
|
-
<h2>${(
|
|
257
|
-
${(
|
|
256
|
+
<h2>${({ props }: CardComponent) => props.title}</h2>
|
|
257
|
+
${({ props }: CardComponent) => props.renderChildren?.()}
|
|
258
258
|
</div>
|
|
259
259
|
`;
|
|
260
260
|
```
|
|
261
261
|
|
|
262
|
-
The interpolations are typed with
|
|
262
|
+
The interpolations are typed by annotating their parameter with the component type (see [Typing template interpolations](#typing-template-interpolations)).
|
|
263
263
|
|
|
264
264
|
`Component.extend` adds the object members to the instance type. Inside its methods, `this` is the extended component, and lifecycle overrides get their parameters typed automatically:
|
|
265
265
|
|
|
@@ -347,15 +347,15 @@ type S = ComponentState<Counter>;
|
|
|
347
347
|
|
|
348
348
|
### Typing template interpolations
|
|
349
349
|
|
|
350
|
-
Functions inside a template are `any` — rasti can't infer them from the surrounding string.
|
|
350
|
+
Functions inside a template are `any` — rasti can't infer them from the surrounding string. How to type one depends on what rasti calls it with, and that depends on where it sits in the template.
|
|
351
351
|
|
|
352
352
|
> Under `strict` / `noImplicitAny`, an untyped interpolation callback is an error (TS7031/TS7006), not a silent `any`. In non-strict mode typing is opt-in.
|
|
353
353
|
|
|
354
|
-
| Interpolation |
|
|
354
|
+
| Interpolation | Called with | Type it with |
|
|
355
355
|
|---|---|---|
|
|
356
|
-
| Content `${fn}` or quoted attr `attr="${fn}"` |
|
|
357
|
-
| Unquoted `onX=${fn}` |
|
|
358
|
-
| Function passed to a child (`handler=${fn}`) |
|
|
356
|
+
| Content `${fn}` or quoted attr `attr="${fn}"` | The component, as its argument and as `this` | An arrow annotated with the component type: `({ props }: C) => …` |
|
|
357
|
+
| Unquoted `onX=${fn}` | `(event, component, matched)`, with `this` the component | `satisfies EventHandler<C, E>` |
|
|
358
|
+
| Function passed to a child (`handler=${fn}`) | Whatever the child calls it with | `satisfies ChildProps['handler']` |
|
|
359
359
|
|
|
360
360
|
The component type `C` is `Component<P, S, M>` with the same generics passed to `create`, aliased next to the component. It is not a copy: it is the exact type of the component's instances.
|
|
361
361
|
|
|
@@ -367,7 +367,7 @@ type ToggleComponent = Component<ToggleProps, ToggleState>;
|
|
|
367
367
|
|
|
368
368
|
const Toggle = Component.create<ToggleProps, ToggleState>`
|
|
369
369
|
<button onClick=${(function() { this.state!.active = !this.state!.active; }) satisfies EventHandler<ToggleComponent, MouseEvent>}>
|
|
370
|
-
${(
|
|
370
|
+
${({ props, state }: ToggleComponent) => `${props.label}: ${state!.active ? 'on' : 'off'}`}
|
|
371
371
|
</button>
|
|
372
372
|
`.extend({
|
|
373
373
|
onCreate() { this.state = new ToggleState({ active: false }); }
|
|
@@ -376,10 +376,16 @@ const Toggle = Component.create<ToggleProps, ToggleState>`
|
|
|
376
376
|
|
|
377
377
|
Inside its own template, a component can't use `InstanceType<typeof Toggle>`: the type of `Toggle` depends on the template itself, so TypeScript reports a circular reference (TS7022).
|
|
378
378
|
|
|
379
|
-
|
|
379
|
+
**Content and quoted attributes** receive the component as their argument, so annotating the parameter types everything they read. A `function` that reads `this` instead needs `satisfies RenderExpression<C>`, which types `this` as well.
|
|
380
|
+
|
|
381
|
+
**Unquoted handlers** receive the event first, not the component. An annotated parameter still compiles there, since the template's expressions are `any`, and fails at runtime. `satisfies` checks the function against what rasti passes it:
|
|
380
382
|
|
|
381
383
|
```ts
|
|
382
|
-
|
|
384
|
+
// Compiles, but the argument is the MouseEvent: `props` is undefined at runtime.
|
|
385
|
+
onClick=${({ props }: ToggleComponent) => console.log(props.label)}
|
|
386
|
+
|
|
387
|
+
// Rejected (TS2339): `props` does not exist on `MouseEvent`.
|
|
388
|
+
onClick=${(({ props }) => console.log(props.label)) satisfies EventHandler<ToggleComponent, MouseEvent>}
|
|
383
389
|
```
|
|
384
390
|
|
|
385
391
|
#### Templates that call the component's own methods
|
|
@@ -401,7 +407,7 @@ class ListBase extends Component<ListProps> {
|
|
|
401
407
|
|
|
402
408
|
const List = ListBase.create`
|
|
403
409
|
<ul onClick=${(function(ev) { this.select(ev); }) satisfies EventHandler<ListBase, MouseEvent>}>
|
|
404
|
-
${(
|
|
410
|
+
${(self: ListBase) => self.renderItems()}
|
|
405
411
|
</ul>
|
|
406
412
|
`;
|
|
407
413
|
|
|
@@ -419,7 +425,7 @@ handleChange=${((checked) => model.toggleAll(checked)) satisfies ToggleAllProps[
|
|
|
419
425
|
|
|
420
426
|
### Known limitations
|
|
421
427
|
|
|
422
|
-
- **Template interpolation callbacks are `any`**. Functions in ``Component.create`...` `` templates can't be inferred from the surrounding string — type them
|
|
428
|
+
- **Template interpolation callbacks are `any`**. Functions in ``Component.create`...` `` templates can't be inferred from the surrounding string — type them by where they sit in the template (see [Typing template interpolations](#typing-template-interpolations)).
|
|
423
429
|
- **A component can't name its own type in its template**. `InstanceType<typeof X>` is circular there (TS7022). Use `Component<P, S, M>` (see [Typing template interpolations](#typing-template-interpolations)), or the class `create` is called on when the template calls its methods (see [Templates that call the component's own methods](#templates-that-call-the-components-own-methods)).
|
|
424
430
|
- **`Model<A>` instance keys require declaration merging**. TypeScript can't add `A`'s keys to a `class extends Model<A>` automatically — see the `interface Todo extends TodoAttrs {}` pattern above.
|
|
425
431
|
- **`this.$()` can return `null`**. It mirrors `querySelector`, so handle the empty case (`?.`) and pass a type argument to narrow the element: `this.$<HTMLInputElement>('input.edit')?.focus()`. `this.$$()` returns a `NodeListOf<HTMLElement>` (also narrowable).
|