rasti 4.1.0-alpha.2 → 4.1.0

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 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.0-alpha.2/docs/logo-dark.svg">
4
- <img alt="Rasti.js" src="https://cdn.jsdelivr.net/gh/8tentaculos/rasti@v4.1.0-alpha.2/docs/logo.svg" height="120">
3
+ <source media="(prefers-color-scheme: dark)" srcset="https://cdn.jsdelivr.net/gh/8tentaculos/rasti@v4.1.0/docs/logo-dark.svg">
4
+ <img alt="Rasti.js" src="https://cdn.jsdelivr.net/gh/8tentaculos/rasti@v4.1.0/docs/logo.svg" height="120">
5
5
  </picture>
6
6
  </p>
7
7
 
@@ -288,7 +288,7 @@ class Scoreboard extends Component<{}, ScoreState> {
288
288
 
289
289
  ### Models
290
290
 
291
- Type the attributes with `Model<Attrs>`. Use **declaration merging** to surface the auto-generated getters/setters as instance properties:
291
+ Type the attributes with `Model<YourAttrs>`. Use **declaration merging** to surface the auto-generated getters/setters as instance properties:
292
292
 
293
293
  ```ts
294
294
  import { Model } from 'rasti';
@@ -314,29 +314,37 @@ t.on('change:completed', (m, value) => value && /* boolean */ console.log('done'
314
314
  import {
315
315
  EventHandler,
316
316
  RenderExpression,
317
- Attrs,
318
- Props,
319
- State,
317
+ ModelAttrs,
318
+ ComponentProps,
319
+ ComponentState,
320
320
  ComponentModel,
321
321
  } from 'rasti';
322
322
 
323
+ // `Counter` (defined above with Component.create) is a *value*. To use the name in
324
+ // type position, alias it once — now `Counter` is both a value and a type:
325
+ type Counter = InstanceType<typeof Counter>;
326
+
323
327
  // Typed event handler with `this` bound to the component
324
328
  const onClick: EventHandler<Counter, MouseEvent> = function(ev) {
325
- this.props.label;
329
+ this.props.initial;
326
330
  };
327
331
 
328
332
  // Typed render expression (`(component) => any`)
329
- const renderLabel: RenderExpression<Counter> = ({ props }) => props.label;
333
+ const renderLabel: RenderExpression<Counter> = ({ props }) => props.initial;
330
334
 
331
335
  // Extract types from existing classes
332
- type T = Attrs<Todo>; // TodoAttrs
333
- type P = Props<Counter>; // CounterProps
334
- type S = State<Counter>; // CounterState
336
+ type A = ModelAttrs<Todo>; // Todo extends Model → already a type, no alias
337
+ type P = ComponentProps<Counter>; // pass the instance; `ComponentProps<typeof Counter>` is `never`
338
+ type S = ComponentState<Counter>;
335
339
  ```
336
340
 
341
+ > Components made with `Component.create` are **values**, not types. To use one as a type — as with `Counter` above — add `type X = InstanceType<typeof X>` next to the definition, or write `InstanceType<typeof X>` inline. A `Model` subclass needs no alias, since `class` already declares both a value and a type.
342
+
337
343
  ### Typing template interpolations
338
344
 
339
- Functions inside a template are `any` — rasti can't infer them from the surrounding string. Typing is **opt-in**: annotate where you want safety, leave the rest as `any`. Which type to use depends on how rasti treats the function (quoted attribute or content → run on render; unquoted attribute → passed as-is):
345
+ Functions inside a template are `any` — rasti can't infer them from the surrounding string. Which type to use depends on how rasti treats the function (quoted attribute or content → run on render; unquoted attribute → passed as-is):
346
+
347
+ > Under `strict` / `noImplicitAny`, every interpolation callback **must** be annotated — an untyped parameter is an error (TS7031/TS7006), not a silent `any`. In non-strict mode typing is opt-in: annotate where you want safety and leave trivial ones as `any`.
340
348
 
341
349
  | Interpolation | What it is | Type to use |
342
350
  |---|---|---|
@@ -347,6 +355,12 @@ Functions inside a template are `any` — rasti can't infer them from the surrou
347
355
  Three ways to apply them:
348
356
 
349
357
  ```ts
358
+ // `Home` is a value (made with Component.create), so alias it to use the name as a type:
359
+ const Home = Component.create<{}, { location: string }>`<div></div>`.extend({
360
+ close() { /* ... */ },
361
+ });
362
+ type Home = InstanceType<typeof Home>;
363
+
350
364
  // 1. Named const — cleanest for non-trivial handlers
351
365
  const onClick: EventHandler<Home, MouseEvent> = function(ev, self) {
352
366
  ev.preventDefault();
@@ -354,10 +368,10 @@ const onClick: EventHandler<Home, MouseEvent> = function(ev, self) {
354
368
  };
355
369
 
356
370
  // 2. Inline with `satisfies` — checks + types the params without widening
357
- ${(({ state }) => state.location) satisfies RenderExpression<Home>}
371
+ ${(({ state }) => state?.location) satisfies RenderExpression<Home>}
358
372
 
359
373
  // 3. Bare annotation — lightest, just types the argument
360
- ${({ state }: Home) => state.location}
374
+ ${({ state }: Home) => state?.location}
361
375
  ```
362
376
 
363
377
  For a function passed to a child, neither helper fits — its type comes from the child's prop. Type it against that prop's declared type (rasti can't connect the attribute to the child, since both live inside the template string):
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rasti",
3
- "version": "4.1.0-alpha.2",
3
+ "version": "4.1.0",
4
4
  "description": "Modern MVC for building user interfaces",
5
5
  "type": "module",
6
6
  "main": "lib/index.cjs",
@@ -71,9 +71,9 @@ export type EventHandler<C, E extends Event = Event> = (
71
71
  export type RenderExpression<C> = (this: C, component: C) => any;
72
72
 
73
73
  /** Extracts the props type `P` from a Component subclass. */
74
- export type Props<C> = C extends Component<infer P, any, any> ? P : never;
74
+ export type ComponentProps<C> = C extends Component<infer P, any, any> ? P : never;
75
75
  /** Extracts the state type `S` from a Component subclass. */
76
- export type State<C> = C extends Component<any, infer S, any> ? S : never;
76
+ export type ComponentState<C> = C extends Component<any, infer S, any> ? S : never;
77
77
  /** Extracts the model type `M` from a Component / View subclass. */
78
78
  export type ComponentModel<C> =
79
79
  C extends Component<any, any, infer M> ? M :
package/types/Model.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import Emitter from './Emitter.js';
2
2
 
3
3
  /** Extracts the attribute type `A` from a Model subclass. */
4
- export type Attrs<M> = M extends Model<infer A> ? A : never;
4
+ export type ModelAttrs<M> = M extends Model<infer A> ? A : never;
5
5
 
6
6
  export type ModelEvents<A> =
7
7
  & {
package/types/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  export { default as Emitter, EventMap } from './Emitter.js';
2
- export { default as Model, ModelEvents, Attrs } from './Model.js';
2
+ export { default as Model, ModelEvents, ModelAttrs } from './Model.js';
3
3
  export { default as View, ViewOptions } from './View.js';
4
4
  export {
5
5
  default as Component,
@@ -9,8 +9,8 @@ export {
9
9
  ComponentPartial,
10
10
  EventHandler,
11
11
  RenderExpression,
12
- Props,
13
- State,
12
+ ComponentProps,
13
+ ComponentState,
14
14
  ComponentModel,
15
15
  ComponentLifecycle,
16
16
  ExtendedComponent,