@defold-typescript/types 0.47.0 → 0.48.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/hsm/index.d.ts +112 -92
- package/package.json +1 -1
package/hsm/index.d.ts
CHANGED
|
@@ -134,6 +134,21 @@ export interface AlwaysConfig<Ctx, To extends string = string> {
|
|
|
134
134
|
* whose `when` is missing or passes is taken.
|
|
135
135
|
*/
|
|
136
136
|
export type AlwaysSpec<Ctx, To extends string = string> = To | AlwaysConfig<Ctx, To> | RuleList<AlwaysConfig<Ctx, To>>;
|
|
137
|
+
/**
|
|
138
|
+
* One entry of the list form of `after`: a `delay` and the `to` its timer leads to.
|
|
139
|
+
* @noSelf
|
|
140
|
+
*/
|
|
141
|
+
export interface AfterConfig<Ctx, To extends string = string> {
|
|
142
|
+
/**
|
|
143
|
+
* The delay in seconds of game time: a number, or a function of the context that returns one.
|
|
144
|
+
* A function is read once each time the state is entered, after its `enter` hook, and again on
|
|
145
|
+
* a hot reload, so the delay is fixed for that stay. A result that is not a non-negative number
|
|
146
|
+
* throws, naming the state.
|
|
147
|
+
*/
|
|
148
|
+
readonly delay: number | ((ctx: Ctx) => number);
|
|
149
|
+
/** The full path of the state to move to when the delay has passed. */
|
|
150
|
+
readonly to: To;
|
|
151
|
+
}
|
|
137
152
|
/**
|
|
138
153
|
* A state's rules by event `type`. Only the machine's event types are keys, and each rule's
|
|
139
154
|
* `when` and `run` see the event variant its key names.
|
|
@@ -212,13 +227,17 @@ interface StateBase<Ctx, E extends EventObject, T, Self extends string, To exten
|
|
|
212
227
|
*/
|
|
213
228
|
readonly on?: NoInfer<OnConfig<Ctx, E, To>>;
|
|
214
229
|
/**
|
|
215
|
-
*
|
|
216
|
-
*
|
|
217
|
-
*
|
|
230
|
+
* Timers, in one of two forms: targets by delay in seconds of game time, such as
|
|
231
|
+
* `{ 2: "/idle" }`, or a list of `AfterConfig` entries, such as
|
|
232
|
+
* `[{ delay: (ctx) => ctx.patrolFor, to: "/rest" }]`, whose `delay` is a number or a function
|
|
233
|
+
* of the context. A delay function is read once each time the state is entered, after its
|
|
234
|
+
* `enter` hook, and again on a hot reload. The delay is counted by `update(dt)` while the state
|
|
235
|
+
* is active, from zero on each entry. One `update` call fires at most one timer, and none when
|
|
236
|
+
* an `update` hook moved the machine.
|
|
218
237
|
*/
|
|
219
238
|
readonly after?: NoInfer<{
|
|
220
239
|
readonly [seconds: number]: To;
|
|
221
|
-
}>;
|
|
240
|
+
} | readonly AfterConfig<Ctx, To>[]>;
|
|
222
241
|
/**
|
|
223
242
|
* Targets taken right after any move that leaves this state active; the first whose `when` is
|
|
224
243
|
* missing or passes wins. It is checked after a move only: not after a rule with no `to`, and
|
|
@@ -296,24 +315,33 @@ export type MachineConfig<Ctx, E extends EventObject> = CompoundState<Ctx, E, un
|
|
|
296
315
|
readonly [name: string]: StateConfig<Ctx, E>;
|
|
297
316
|
};
|
|
298
317
|
};
|
|
318
|
+
type WithPrivate<Ctx, Priv> = [Priv] extends [never] ? Ctx : Ctx & Priv;
|
|
299
319
|
/**
|
|
300
320
|
* Defines a machine in two calls: `defineMachine<Ctx, E>()` fixes the context and event types and
|
|
301
321
|
* takes an optional hot-reload key, and the second call takes the config. The config is checked
|
|
302
322
|
* when that call runs, and a mistake throws, naming the state path. With a key, a later
|
|
303
323
|
* definition under it puts its states into the machine already built, so every running instance
|
|
304
324
|
* sees the edit; without one, each call builds a separate machine.
|
|
325
|
+
*
|
|
326
|
+
* The root config may hold `privateCtx`, for a machine that keeps fields of its own, such as a
|
|
327
|
+
* counter, a heat level or a list it builds up. Every hook, `when`, `run`, `task` and `update`
|
|
328
|
+
* then sees those fields beside `Ctx`, while `start` takes only `Ctx` and the instance it returns
|
|
329
|
+
* shows only `Ctx` in its `ctx`. A machine without fields of its own leaves `privateCtx` out.
|
|
305
330
|
*/
|
|
306
|
-
export declare function defineMachine<Ctx, E extends EventObject>(key?: string): <T>(config: RootState<Ctx, E, T>) => Machine<Ctx, E, TreePath<T>>;
|
|
331
|
+
export declare function defineMachine<Ctx, E extends EventObject>(key?: string): <T, Priv extends object = never>(config: RootState<WithPrivate<Ctx, Priv>, E, T> & PrivateCtxConfig<Ctx, Priv>) => Machine<Ctx, E, TreePath<T>>;
|
|
307
332
|
/**
|
|
308
|
-
* The key a `
|
|
333
|
+
* The optional key a `defineMachine` root config takes beside `initial` and `states`.
|
|
309
334
|
* @noSelf
|
|
310
335
|
*/
|
|
311
336
|
export interface PrivateCtxConfig<Ctx, Priv> {
|
|
312
337
|
/**
|
|
313
338
|
* Builds the fields only the machine uses. It runs once per `start`, before the root's `enter`
|
|
314
339
|
* hook, so every instance gets fresh fields of its own; a value written straight into the
|
|
315
|
-
* config would be one array or table shared by every instance. It
|
|
316
|
-
* a private field from a field of `Ctx
|
|
340
|
+
* config would be one array or table shared by every instance. It receives the object passed
|
|
341
|
+
* to `start`, typed `Ctx`, so a private field can start from a field of `Ctx`:
|
|
342
|
+
* `privateCtx: (ctx: TurretOptions) => ({ heat: ctx.startHeat })`. Give `ctx` its type; without
|
|
343
|
+
* one TypeScript can type a hook before it knows the private fields, and that hook reports the
|
|
344
|
+
* field as missing.
|
|
317
345
|
*
|
|
318
346
|
* The fields are added to the object passed to `start`, which stays the instance's `ctx`, so
|
|
319
347
|
* restarting with `start(old.ctx)` keeps the public fields and builds the private ones fresh.
|
|
@@ -323,92 +351,84 @@ export interface PrivateCtxConfig<Ctx, Priv> {
|
|
|
323
351
|
*
|
|
324
352
|
* The fields are hidden from callers by type only. At run time `ctx` is one table, and hooks,
|
|
325
353
|
* `hsm-view` and a debugger see every field.
|
|
354
|
+
*
|
|
355
|
+
* There are two ways to type the fields.
|
|
356
|
+
*
|
|
357
|
+
* @example
|
|
358
|
+
* **Inferred.** For a few fields, write them inline and let TypeScript infer their types. Add
|
|
359
|
+
* `as` where the inferred type is wrong: an empty array is `never[]` until it reads
|
|
360
|
+
* `[] as Hash[]`, and a field holding one of several strings is any `string` until it reads
|
|
361
|
+
* `"cool" as "cool" | "hot"`.
|
|
362
|
+
*
|
|
363
|
+
* ```ts
|
|
364
|
+
* type TurretEvent = { type: "SPOTTED" } | { type: "LOST" };
|
|
365
|
+
*
|
|
366
|
+
* export const turret = defineMachine<{ readonly fireRate: number }, TurretEvent>("turret")({
|
|
367
|
+
* privateCtx: () => ({ heat: 0, targets: [] as Hash[] }),
|
|
368
|
+
* initial: "/idle",
|
|
369
|
+
* states: {
|
|
370
|
+
* idle: { on: { SPOTTED: "/firing" } },
|
|
371
|
+
* firing: {
|
|
372
|
+
* enter: (ctx) => {
|
|
373
|
+
* ctx.heat += 1 / ctx.fireRate;
|
|
374
|
+
* },
|
|
375
|
+
* on: { LOST: "/idle" },
|
|
376
|
+
* },
|
|
377
|
+
* },
|
|
378
|
+
* });
|
|
379
|
+
*
|
|
380
|
+
* const gun = turret.start({ fireRate: 2 }); // gun.ctx shows fireRate only
|
|
381
|
+
* ```
|
|
382
|
+
*
|
|
383
|
+
* @example
|
|
384
|
+
* **A named type.** For more fields, or when a helper outside the config needs the whole
|
|
385
|
+
* context, declare the fields as an interface and make it the factory's return type. The
|
|
386
|
+
* fields need no `as`, a misspelled or unknown field is a compile error, and the whole context
|
|
387
|
+
* is `TurretOptions & TurretPrivate`. `satisfies TurretPrivate` does not do this: it checks the
|
|
388
|
+
* object but keeps its narrow types, so an empty array stays `never[]`.
|
|
389
|
+
*
|
|
390
|
+
* ```ts
|
|
391
|
+
* interface TurretOptions {
|
|
392
|
+
* readonly fireRate: number;
|
|
393
|
+
* }
|
|
394
|
+
*
|
|
395
|
+
* interface TurretPrivate {
|
|
396
|
+
* heat: number;
|
|
397
|
+
* mode: "cool" | "hot";
|
|
398
|
+
* }
|
|
399
|
+
*
|
|
400
|
+
* type TurretEvent = { type: "SPOTTED" } | { type: "LOST" };
|
|
401
|
+
*
|
|
402
|
+
* const overheated = (ctx: TurretOptions & TurretPrivate) => ctx.heat > ctx.fireRate;
|
|
403
|
+
*
|
|
404
|
+
* export const turret = defineMachine<TurretOptions, TurretEvent>("turret")({
|
|
405
|
+
* privateCtx: (): TurretPrivate => ({ heat: 0, mode: "cool" }),
|
|
406
|
+
* initial: "/idle",
|
|
407
|
+
* states: {
|
|
408
|
+
* idle: { on: { SPOTTED: "/firing" } },
|
|
409
|
+
* firing: {
|
|
410
|
+
* enter: (ctx) => {
|
|
411
|
+
* ctx.heat += 1 / ctx.fireRate;
|
|
412
|
+
* },
|
|
413
|
+
* always: { to: "/cooling", when: overheated },
|
|
414
|
+
* on: { LOST: "/idle" },
|
|
415
|
+
* },
|
|
416
|
+
* cooling: {
|
|
417
|
+
* enter: (ctx) => {
|
|
418
|
+
* ctx.mode = "hot";
|
|
419
|
+
* },
|
|
420
|
+
* exit: (ctx) => {
|
|
421
|
+
* ctx.heat = 0;
|
|
422
|
+
* ctx.mode = "cool";
|
|
423
|
+
* },
|
|
424
|
+
* after: { 2: "/idle" },
|
|
425
|
+
* },
|
|
426
|
+
* },
|
|
427
|
+
* });
|
|
428
|
+
* ```
|
|
326
429
|
*/
|
|
327
|
-
readonly privateCtx:
|
|
430
|
+
readonly privateCtx?: (ctx: Ctx) => Priv & {
|
|
328
431
|
readonly [K in keyof Ctx & keyof Priv]: never;
|
|
329
432
|
};
|
|
330
433
|
}
|
|
331
|
-
/**
|
|
332
|
-
* Like `defineMachine`, for a machine that keeps fields of its own, such as a counter, a heat
|
|
333
|
-
* level or a list it builds up. The config's `privateCtx` returns those fields. Every hook,
|
|
334
|
-
* `when`, `run`, `task` and `update` sees them beside `Ctx`, while `start` takes only `Ctx` and
|
|
335
|
-
* the instance it returns shows only `Ctx` in its `ctx`. A machine without fields of its own
|
|
336
|
-
* uses `defineMachine`.
|
|
337
|
-
*
|
|
338
|
-
* There are two ways to type the fields.
|
|
339
|
-
*
|
|
340
|
-
* @example
|
|
341
|
-
* **Inferred.** For a few fields, write them inline and let TypeScript infer their types. Add
|
|
342
|
-
* `as` where the inferred type is wrong: an empty array is `never[]` until it reads
|
|
343
|
-
* `[] as Hash[]`, and a field holding one of several strings is any `string` until it reads
|
|
344
|
-
* `"cool" as "cool" | "hot"`.
|
|
345
|
-
*
|
|
346
|
-
* ```ts
|
|
347
|
-
* type TurretEvent = { type: "SPOTTED" } | { type: "LOST" };
|
|
348
|
-
*
|
|
349
|
-
* export const turret = definePrivateMachine<{ readonly fireRate: number }, TurretEvent>("turret")({
|
|
350
|
-
* privateCtx: () => ({ heat: 0, targets: [] as Hash[] }),
|
|
351
|
-
* initial: "/idle",
|
|
352
|
-
* states: {
|
|
353
|
-
* idle: { on: { SPOTTED: "/firing" } },
|
|
354
|
-
* firing: {
|
|
355
|
-
* enter: (ctx) => {
|
|
356
|
-
* ctx.heat += 1 / ctx.fireRate;
|
|
357
|
-
* },
|
|
358
|
-
* on: { LOST: "/idle" },
|
|
359
|
-
* },
|
|
360
|
-
* },
|
|
361
|
-
* });
|
|
362
|
-
*
|
|
363
|
-
* const gun = turret.start({ fireRate: 2 }); // gun.ctx shows fireRate only
|
|
364
|
-
* ```
|
|
365
|
-
*
|
|
366
|
-
* @example
|
|
367
|
-
* **A named type.** For more fields, or when a helper outside the config needs the whole
|
|
368
|
-
* context, declare the fields as an interface and make it the factory's return type. The fields
|
|
369
|
-
* need no `as`, a misspelled or unknown field is a compile error, and the whole context is
|
|
370
|
-
* `TurretOptions & TurretPrivate`. `satisfies TurretPrivate` does not do this: it checks the
|
|
371
|
-
* object but keeps its narrow types, so an empty array stays `never[]`.
|
|
372
|
-
*
|
|
373
|
-
* ```ts
|
|
374
|
-
* interface TurretOptions {
|
|
375
|
-
* readonly fireRate: number;
|
|
376
|
-
* }
|
|
377
|
-
*
|
|
378
|
-
* interface TurretPrivate {
|
|
379
|
-
* heat: number;
|
|
380
|
-
* mode: "cool" | "hot";
|
|
381
|
-
* }
|
|
382
|
-
*
|
|
383
|
-
* type TurretEvent = { type: "SPOTTED" } | { type: "LOST" };
|
|
384
|
-
*
|
|
385
|
-
* const overheated = (ctx: TurretOptions & TurretPrivate) => ctx.heat > ctx.fireRate;
|
|
386
|
-
*
|
|
387
|
-
* export const turret = definePrivateMachine<TurretOptions, TurretEvent>("turret")({
|
|
388
|
-
* privateCtx: (): TurretPrivate => ({ heat: 0, mode: "cool" }),
|
|
389
|
-
* initial: "/idle",
|
|
390
|
-
* states: {
|
|
391
|
-
* idle: { on: { SPOTTED: "/firing" } },
|
|
392
|
-
* firing: {
|
|
393
|
-
* enter: (ctx) => {
|
|
394
|
-
* ctx.heat += 1 / ctx.fireRate;
|
|
395
|
-
* },
|
|
396
|
-
* always: { to: "/cooling", when: overheated },
|
|
397
|
-
* on: { LOST: "/idle" },
|
|
398
|
-
* },
|
|
399
|
-
* cooling: {
|
|
400
|
-
* enter: (ctx) => {
|
|
401
|
-
* ctx.mode = "hot";
|
|
402
|
-
* },
|
|
403
|
-
* exit: (ctx) => {
|
|
404
|
-
* ctx.heat = 0;
|
|
405
|
-
* ctx.mode = "cool";
|
|
406
|
-
* },
|
|
407
|
-
* after: { 2: "/idle" },
|
|
408
|
-
* },
|
|
409
|
-
* },
|
|
410
|
-
* });
|
|
411
|
-
* ```
|
|
412
|
-
*/
|
|
413
|
-
export declare const definePrivateMachine: <Ctx, E extends EventObject>(key?: string) => <T, Priv extends object>(config: RootState<Ctx & Priv, E, T> & PrivateCtxConfig<Ctx, Priv>) => Machine<Ctx, E, TreePath<T>>;
|
|
414
434
|
export {};
|