diff --git a/.changeset/six-crabs-hang.md b/.changeset/six-crabs-hang.md new file mode 100644 index 0000000000..eae10da253 --- /dev/null +++ b/.changeset/six-crabs-hang.md @@ -0,0 +1,5 @@ +--- +'xstate': minor +--- + +The TypeGen-related types have been removed from XState, simplifying the internal types without affecting normal XState usage. diff --git a/packages/core/src/State.ts b/packages/core/src/State.ts index 597ca1124f..78156a13a8 100644 --- a/packages/core/src/State.ts +++ b/packages/core/src/State.ts @@ -3,7 +3,6 @@ import { $$ACTOR_TYPE } from './createActor.ts'; import type { StateNode } from './StateNode.ts'; import type { StateMachine } from './StateMachine.ts'; import { getStateValue } from './stateUtils.ts'; -import { TypegenDisabled } from './typegenTypes.ts'; import type { ProvidedActor, AnyMachineSnapshot, diff --git a/packages/core/src/StateMachine.ts b/packages/core/src/StateMachine.ts index d204aff983..3d7fa7cb32 100644 --- a/packages/core/src/StateMachine.ts +++ b/packages/core/src/StateMachine.ts @@ -22,7 +22,6 @@ import { transitionNode } from './stateUtils.ts'; import { AnyActorSystem } from './system.ts'; -import { ResolveTypegenMeta, TypegenDisabled } from './typegenTypes.ts'; import type { ActorLogic, ActorScope, @@ -46,7 +45,8 @@ import type { SnapshotFrom, StateMachineDefinition, StateValue, - TransitionDefinition + TransitionDefinition, + ResolvedStateMachineTypes } from './types.ts'; import { resolveReferencedActor, toStatePath } from './utils.ts'; @@ -66,17 +66,7 @@ export class StateMachine< TInput, TOutput, TEmitted extends EventObject = EventObject, // TODO: remove default - TMeta extends MetaObject = MetaObject, - TResolvedTypesMeta = ResolveTypegenMeta< - TypegenDisabled, - DoNotInfer, - TActor, - TAction, - TGuard, - TDelay, - TTag, - TEmitted - > + TMeta extends MetaObject = MetaObject > implements ActorLogic< MachineSnapshot< @@ -187,9 +177,16 @@ export class StateMachine< */ public provide( implementations: InternalMachineImplementations< - TContext, - TResolvedTypesMeta, - true + ResolvedStateMachineTypes< + TContext, + DoNotInfer, + TActor, + TAction, + TGuard, + TDelay, + TTag, + TEmitted + > > ): StateMachine< TContext, @@ -204,8 +201,7 @@ export class StateMachine< TInput, TOutput, TEmitted, - TMeta, // TMeta - TResolvedTypesMeta + TMeta > { const { actions, guards, actors, delays } = this.implementations; @@ -619,9 +615,4 @@ export class StateMachine< return restoredSnapshot; } - - /** - * @deprecated an internal property that was acting as a "phantom" type, it's not used by anything right now but it's kept around for compatibility reasons - **/ - __TResolvedTypesMeta!: TResolvedTypesMeta; } diff --git a/packages/core/src/StateNode.ts b/packages/core/src/StateNode.ts index b001022f6a..2cc4dc676e 100644 --- a/packages/core/src/StateNode.ts +++ b/packages/core/src/StateNode.ts @@ -125,12 +125,12 @@ export class StateNode< any, // action any, // guard any, // delay + any, // state value any, // tag any, // input any, // output any, // emitted - any, // TMeta - any // typegen + any // meta >; /** * The meta data associated with this state node, which will be returned in State instances. diff --git a/packages/core/src/createMachine.ts b/packages/core/src/createMachine.ts index 071cfed8f1..f1f6cd2721 100644 --- a/packages/core/src/createMachine.ts +++ b/packages/core/src/createMachine.ts @@ -1,9 +1,5 @@ import { StateMachine } from './StateMachine.ts'; -import { - ResolveTypegenMeta, - TypegenConstraint, - TypegenDisabled -} from './typegenTypes.ts'; +import { ResolvedStateMachineTypes } from './types.ts'; import { AnyActorRef, EventObject, @@ -16,7 +12,6 @@ import { MachineTypes, NonReducibleUnknown, ParameterizedObject, - Prop, ProvidedActor, StateValue, ToChildren, @@ -122,7 +117,7 @@ export function createMachine< // it's important to have at least one default type parameter here // it allows us to benefit from contextual type instantiation as it makes us to pass the hasInferenceCandidatesOrDefault check in the compiler // we should be able to remove this when we start inferring TConfig, with it we'll always have an inference candidate - TTypesMeta extends TypegenConstraint = TypegenDisabled + _ = any >( config: { types?: MachineTypes< @@ -136,8 +131,7 @@ export function createMachine< TInput, TOutput, TEmitted, - TMeta, - TTypesMeta + TMeta >; schemas?: unknown; } & MachineConfig< @@ -151,13 +145,11 @@ export function createMachine< TInput, TOutput, TEmitted, - TMeta, - TTypesMeta + TMeta >, implementations?: InternalMachineImplementations< - TContext, - ResolveTypegenMeta< - TTypesMeta, + ResolvedStateMachineTypes< + TContext, TEvent, TActor, TAction, @@ -175,37 +167,12 @@ export function createMachine< TAction, TGuard, TDelay, - 'matchesStates' extends keyof TTypesMeta - ? ToStateValue> - : StateValue, - Prop< - ResolveTypegenMeta< - TTypesMeta, - TEvent, - TActor, - TAction, - TGuard, - TDelay, - TTag, - TEmitted - >['resolved'], - 'tags' - > & - string, + StateValue, + TTag & string, TInput, TOutput, TEmitted, - TMeta, // TMeta - ResolveTypegenMeta< - TTypesMeta, - TEvent, - TActor, - TAction, - TGuard, - TDelay, - TTag, - TEmitted - > + TMeta // TMeta > { return new StateMachine< any, @@ -220,7 +187,6 @@ export function createMachine< any, any, any, // TEmitted - any, // TMeta - any + any // TMeta >(config as any, implementations as any); } diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index 8412689310..e2a1ca4dfd 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -5,7 +5,6 @@ export { type Spawner } from './spawn.ts'; export { isMachineSnapshot, type MachineSnapshot } from './State.ts'; export { StateMachine } from './StateMachine.ts'; export { getStateNodes } from './stateUtils.ts'; -export * from './typegenTypes.ts'; export * from './types.ts'; export { waitFor } from './waitFor.ts'; import { createMachine } from './createMachine.ts'; diff --git a/packages/core/src/setup.ts b/packages/core/src/setup.ts index 0ab6144013..5ad6708805 100644 --- a/packages/core/src/setup.ts +++ b/packages/core/src/setup.ts @@ -1,7 +1,7 @@ import { StateMachine } from './StateMachine'; import { createMachine } from './createMachine'; import { GuardPredicate } from './guards'; -import { ResolveTypegenMeta, TypegenDisabled } from './typegenTypes'; + import { ActionFunction, AnyActorRef, @@ -196,17 +196,7 @@ export function setup< TInput, TOutput, TEmitted, - TMeta, - ResolveTypegenMeta< - TypegenDisabled, - TEvent, - ToProvidedActor, - ToParameterizedObject, - ToParameterizedObject, - TDelay, - TTag, - TEmitted - > + TMeta > >( config: TConfig @@ -226,17 +216,7 @@ export function setup< TInput, TOutput, TEmitted, - TMeta, - ResolveTypegenMeta< - TypegenDisabled, - TEvent, - ToProvidedActor, - ToParameterizedObject, - ToParameterizedObject, - TDelay, - TTag, - TEmitted - > + TMeta >; } { return { diff --git a/packages/core/src/spawn.ts b/packages/core/src/spawn.ts index 6533e6a34b..749bb9faa4 100644 --- a/packages/core/src/spawn.ts +++ b/packages/core/src/spawn.ts @@ -7,6 +7,7 @@ import { AnyEventObject, AnyMachineSnapshot, ConditionalRequired, + GetConcreteByKey, InputFrom, IsLiteralString, IsNotNever, @@ -35,14 +36,6 @@ type SpawnOptions< > : never; -// it's likely-ish that `(TActor & { src: TSrc })['logic']` would be faster -// but it's only possible to do it since https://github.com/microsoft/TypeScript/pull/53098 (TS 5.1) -// and we strive to support TS 5.0 whenever possible -type GetConcreteLogic< - TActor extends ProvidedActor, - TSrc extends TActor['src'] -> = Extract['logic']; - export type Spawner = IsLiteralString< TActor['src'] > extends true @@ -50,7 +43,7 @@ export type Spawner = IsLiteralString< ( logic: TSrc, ...[options]: SpawnOptions - ): ActorRefFrom>; + ): ActorRefFrom['logic']>; ( src: TLogic, options?: { diff --git a/packages/core/src/typegenTypes.ts b/packages/core/src/typegenTypes.ts deleted file mode 100644 index a3963d3a9a..0000000000 --- a/packages/core/src/typegenTypes.ts +++ /dev/null @@ -1,274 +0,0 @@ -import { - EventObject, - IndexByType, - IsNever, - Prop, - ParameterizedObject, - ProvidedActor, - OutputFrom, - AnyActorLogic, - IndexByProp -} from './types.ts'; - -/** - * @deprecated - */ -export interface TypegenDisabled { - '@@xstate/typegen': false; -} - -/** - * @deprecated - */ -export interface TypegenEnabled { - '@@xstate/typegen': true; -} - -/** - * @deprecated - */ -export interface TypegenMeta extends TypegenEnabled { - /** - * Allows you to specify all the results of state.matches - */ - matchesStates: string | {}; - /** - * Allows you to specify all tags used by the machine - */ - tags: string; - /** - * Allows you to specify all the missing implementations - * of the machine - */ - missingImplementations: { - actions: string; - actors: string; - delays: string; - guards: string; - }; - /** - * A map for the internal events of the machine. - * - * ```js - * key: 'xstate.done.actor.myActor' - * value: { - * type: 'xstate.done.actor.myActor'; - * data: unknown; - * __tip: 'Declare the type in event types!'; - * } - * ``` - */ - internalEvents: {}; - /** - * Maps the src of the invoked actor to the event type that includes its known id - * - * key: 'invokeSrc' - * value: 'xstate.done.actor.invokeName' - */ - invokeSrcNameMap: Record; - /** - * Keeps track of which events lead to which - * actions. - * - * Key: 'EVENT_NAME' - * Value: 'actionName' | 'otherActionName' - */ - eventsCausingActions: Record; - /** - * Keeps track of which events lead to which - * delays. - * - * Key: 'EVENT_NAME' - * Value: 'delayName' | 'otherDelayName' - */ - eventsCausingDelays: Record; - /** - * Keeps track of which events lead to which - * guards. - * - * Key: 'EVENT_NAME' - * Value: 'guardName' | 'otherGuardName' - */ - eventsCausingGuards: Record; - /** - * Keeps track of which events lead to which - * actors. - * - * Key: 'EVENT_NAME' - * Value: 'actorName' | 'otherActorName' - */ - eventsCausingActors: Record; -} - -/** - * @deprecated - */ -export interface ResolvedTypegenMeta extends TypegenMeta { - resolved: TypegenMeta & { - indexedActors: Record; - indexedActions: Record; - indexedEvents: Record; - indexedGuards: Record; - indexedDelays: Record; - }; -} - -/** - * @deprecated - */ -export type TypegenConstraint = TypegenEnabled | TypegenDisabled; - -/** - * @deprecated Always resolves to `true` - */ -export type AreAllImplementationsAssumedToBeProvided< - _TResolvedTypesMeta, - _TMissingImplementations = never -> = true; - -/** - * @deprecated Always resolves to `never` - */ -export type MissingImplementationsError< - _TResolvedTypesMeta, - _TMissingImplementations = never -> = never; - -/** - * @deprecated - */ -interface AllImplementationsProvided { - missingImplementations: { - actions: never; - actors: never; - delays: never; - guards: never; - }; -} - -type GenerateActorEvents< - TActor extends ProvidedActor, - TInvokeSrcNameMap -> = string extends TActor['src'] - ? // TActor is pretty much required if one wants to have actor types - // using never here allows typegen to inject internal events with "hints" that the actor type is missing - never - : // distribute over union - TActor extends any - ? { - type: // 1. if the actor has an id, use that - TActor['id'] extends string - ? `xstate.done.actor.${TActor['id']}` - : // 2. if the ids were inferred by typegen then use those - // this doesn't contain *all* possible event types since we can't track spawned actors today - // however, those xstate.done.actor events shouldn't exactly be usable by/surface to the user anyway - TActor['src'] extends keyof TInvokeSrcNameMap - ? `xstate.done.actor.${TInvokeSrcNameMap[TActor['src']] & string}` - : // 3. finally use the fallback type - `xstate.done.actor.${string}`; - output: OutputFrom; - } - : never; - -// we don't even have to do that much here, technically, because `T & unknown` is equivalent to `T` -// however, this doesn't display nicely in IDE tooltips, so let's fix this -type MergeWithInternalEvents = TIndexedEvents & - // alternatively we could consider using key remapping in mapped types for this in the future - // in theory it would be a single iteration rather than two - Pick>; - -type AllowAllEvents = { - eventsCausingActions: Record; - eventsCausingActors: Record; - eventsCausingDelays: Record; - eventsCausingGuards: Record; -}; - -type IndexParameterizedImplementation< - TParameterizedImplementation extends ParameterizedObject, - TCausingLookup -> = string extends TParameterizedImplementation['type'] - ? // this ensures that we can error on provided implementations when no implementations could be inferred by typegen - // technically, it's not even a type issue to accept them since we just won't try to execute them - // that is - if our typegen would be 100% correct and if it could actually handle all scenarios that we consider valid - // (or at least if it would error on the ones that we can't handle) - // it should still be at least a lint warning or something if the user provides an implementation that can't be executed - // so there is still value in this - but we can reevaluate this later - // note that we don't exactly do the same right now when `TAction`/`TGuard`/etc *is* provided together with typegen information - // so the behavior around this could be considered inconsistent (one way or another: either we should always error or we shouldn't error at all) - IsNever extends true - ? never - : Record - : IndexByType; - -type WrapIntoParameterizedObject = T extends any - ? { type: T } - : never; - -/** - * @deprecated - */ -export interface ResolveTypegenMeta< - TTypesMeta extends TypegenConstraint, - TEvent extends EventObject, - TActor extends ProvidedActor, - TAction extends ParameterizedObject, - TGuard extends ParameterizedObject, - TDelay extends string, - TTag extends string, - TEmitted extends EventObject = EventObject -> { - '@@xstate/typegen': TTypesMeta['@@xstate/typegen']; - resolved: { - enabled: TTypesMeta & { - indexedActions: IndexParameterizedImplementation< - TAction, - Prop - >; - // we could add `id` based on typegen information (in both branches) - // but it doesn't seem to be needed for anything right now - indexedActors: string extends TActor['src'] - ? Record< - keyof Prop, - { logic: AnyActorLogic } - > - : IndexByProp; - indexedEvents: MergeWithInternalEvents< - IndexByType< - | (string extends TEvent['type'] ? never : TEvent) - | GenerateActorEvents> - >, - Prop - >; - indexedGuards: IndexParameterizedImplementation< - TGuard, - Prop - >; - // delays are not parameterized but we can reuse this helper and the style of helpers depending on this if we convert delays to paremeterized objects here - // if we ever decide to allow parameterized delays then we'll only have to adjust this place which is nice - indexedDelays: IndexParameterizedImplementation< - WrapIntoParameterizedObject, - Prop - >; - tags: string extends TTag ? Prop : TTag; - emitted: TEmitted; - }; - disabled: TypegenDisabled & - AllImplementationsProvided & - AllowAllEvents & { - indexedActions: IndexByType; - indexedActors: IndexByProp; - // we don't have to iterate through this since we'll never index a concrete event type on this without the typegen meta - indexedEvents: Record; - indexedGuards: IndexByType; - indexedDelays: IndexByType>; - invokeSrcNameMap: Record; - tags: TTag; - emitted: TEmitted; - }; - }[IsNever extends true - ? 'disabled' - : TTypesMeta['@@xstate/typegen'] extends true - ? 'enabled' - : 'disabled']; -} diff --git a/packages/core/src/types.ts b/packages/core/src/types.ts index 3c65d04ca6..34049782fa 100644 --- a/packages/core/src/types.ts +++ b/packages/core/src/types.ts @@ -8,11 +8,6 @@ import type { Actor, ProcessingStatus } from './createActor.ts'; import { Spawner } from './spawn.ts'; import { AnyActorSystem, Clock } from './system.js'; import { InspectionEvent } from './inspection.ts'; -import { - ResolveTypegenMeta, - TypegenConstraint, - TypegenDisabled -} from './typegenTypes.ts'; export type Identity = { [K in keyof T]: T[K] }; @@ -148,8 +143,7 @@ export type InputFrom = T extends StateMachine< infer TInput, infer _TOutput, infer _TEmitted, - infer _TMeta, - infer _TResolvedTypesMeta + infer _TMeta > ? TInput : T extends ActorLogic< @@ -1134,8 +1128,7 @@ export type AnyStateMachine = StateMachine< any, // input any, // output any, // emitted - any, // TMeta - any // typegen + any // TMeta >; export type AnyStateConfig = StateConfig; @@ -1259,239 +1252,55 @@ export interface MachineImplementationsSimplified< delays: DelayFunctionMap; } -type MaybeNarrowedEvent = Cast< - Prop< - TIndexedEvents, - K extends keyof TCausingLookup - ? TCausingLookup[K] - : TIndexedEvents[keyof TIndexedEvents] - >, - EventObject ->; - -type MachineImplementationsActions< - TContext extends MachineContext, - TResolvedTypesMeta, - TEventsCausingActions = Prop< - Prop, - 'eventsCausingActions' - >, - TIndexedEvents = Prop, 'indexedEvents'>, - TIndexedActors = Prop, 'indexedActors'>, - TIndexedActions = Prop< - Prop, - 'indexedActions' - >, - TIndexedGuards = Prop, 'indexedGuards'>, - TIndexedDelays = Prop, 'indexedDelays'>, - TEmitted = Prop, 'emitted'> -> = { - [K in keyof TIndexedActions]?: ActionFunction< - TContext, - MaybeNarrowedEvent, - Cast, EventObject>, - GetParameterizedParams>, - Cast, ProvidedActor>, - Cast, ParameterizedObject>, - Cast, ParameterizedObject>, - Cast< - Prop, - ParameterizedObject - >['type'], - Cast +type MachineImplementationsActions = { + [K in TTypes['actions']['type']]?: ActionFunction< + TTypes['context'], + TTypes['events'], + TTypes['events'], + GetConcreteByKey['params'], + TTypes['actors'], + TTypes['actions'], + TTypes['guards'], + TTypes['delays'], + TTypes['emitted'] >; }; -type MachineImplementationsActors< - _TContext extends MachineContext, - TResolvedTypesMeta, - TIndexedActors = Prop, 'indexedActors'>, - _TInvokeSrcNameMap = Prop< - Prop, - 'invokeSrcNameMap' - > -> = { - [K in keyof TIndexedActors]?: Cast< - Prop, - AnyActorLogic - >; +type MachineImplementationsActors = { + [K in TTypes['actors']['src']]?: GetConcreteByKey< + TTypes['actors'], + 'src', + K + >['logic']; }; -type MachineImplementationsDelays< - TContext extends MachineContext, - TResolvedTypesMeta, - TEventsCausingDelays = Prop< - Prop, - 'eventsCausingDelays' - >, - TIndexedEvents = Prop, 'indexedEvents'>, - TIndexedActions = Prop< - Prop, - 'indexedActions' - >, - TIndexedDelays = Prop, 'indexedDelays'> -> = { - [K in keyof TIndexedDelays]?: DelayConfig< - TContext, - MaybeNarrowedEvent, +type MachineImplementationsDelays = { + [K in TTypes['delays']]?: DelayConfig< + TTypes['context'], + TTypes['events'], // delays in referenced send actions might use specific `TAction` // delays executed by auto-generated send actions related to after transitions won't have that // since they are effectively implicit inline actions - | Cast< - Prop, 'params'>, - ParameterizedObject['params'] | undefined - > - | undefined, - Cast, EventObject> + undefined, + TTypes['events'] >; }; -type MachineImplementationsGuards< - TContext extends MachineContext, - TResolvedTypesMeta, - TEventsCausingGuards = Prop< - Prop, - 'eventsCausingGuards' - >, - TIndexedEvents = Prop, 'indexedEvents'>, - TIndexedGuards = Prop, 'indexedGuards'> -> = { - [K in keyof TIndexedGuards]?: Guard< - TContext, - MaybeNarrowedEvent, - GetParameterizedParams< - Cast - >, - Cast, ParameterizedObject> +type MachineImplementationsGuards = { + [K in TTypes['guards']['type']]?: Guard< + TTypes['context'], + TTypes['events'], + GetConcreteByKey['params'], + TTypes['guards'] >; }; -type MakeKeysRequired = { [K in T]: unknown }; - -type MaybeMakeMissingImplementationsRequired< - TImplementationType, - TMissingImplementationsForType, - TRequireMissingImplementations -> = TRequireMissingImplementations extends true - ? IsNever extends true - ? {} - : { - [K in Cast]: MakeKeysRequired< - Cast - >; - } - : {}; - -type GenerateActionsImplementationsPart< - TContext extends MachineContext, - TResolvedTypesMeta, - TRequireMissingImplementations, - TMissingImplementations -> = Compute< - MaybeMakeMissingImplementationsRequired< - 'actions', - Prop, - TRequireMissingImplementations - > & { - actions?: MachineImplementationsActions; - } ->; - -type GenerateActorsImplementationsPart< - TContext extends MachineContext, - TResolvedTypesMeta, - TRequireMissingImplementations, - TMissingImplementations -> = Compute< - MaybeMakeMissingImplementationsRequired< - 'actors', - Prop, - TRequireMissingImplementations - > & { - actors?: MachineImplementationsActors; - } ->; - -type GenerateDelaysImplementationsPart< - TContext extends MachineContext, - TResolvedTypesMeta, - TRequireMissingImplementations, - TMissingImplementations -> = Compute< - MaybeMakeMissingImplementationsRequired< - 'delays', - Prop, - TRequireMissingImplementations - > & { - delays?: MachineImplementationsDelays; - } ->; - -type GenerateGuardsImplementationsPart< - TContext extends MachineContext, - TResolvedTypesMeta, - TRequireMissingImplementations, - TMissingImplementations -> = Compute< - MaybeMakeMissingImplementationsRequired< - 'guards', - Prop, - TRequireMissingImplementations - > & { - guards?: MachineImplementationsGuards; - } ->; - -export type InternalMachineImplementations< - TContext extends MachineContext, - TResolvedTypesMeta, - TRequireMissingImplementations extends boolean = false, - TMissingImplementations = Prop< - Prop, - 'missingImplementations' - > -> = - // TODO: remove per-Generate* Computes - Compute< - GenerateActionsImplementationsPart< - TContext, - TResolvedTypesMeta, - TRequireMissingImplementations, - TMissingImplementations - > & - GenerateActorsImplementationsPart< - TContext, - TResolvedTypesMeta, - TRequireMissingImplementations, - TMissingImplementations - > & - GenerateDelaysImplementationsPart< - TContext, - TResolvedTypesMeta, - TRequireMissingImplementations, - TMissingImplementations - > & - GenerateGuardsImplementationsPart< - TContext, - TResolvedTypesMeta, - TRequireMissingImplementations, - TMissingImplementations - > - >; - -export type MachineImplementations< - TContext extends MachineContext, - TEvent extends EventObject, - TActor extends ProvidedActor = ProvidedActor, - TAction extends ParameterizedObject = ParameterizedObject, - TGuard extends ParameterizedObject = ParameterizedObject, - TDelay extends string = string, - TTag extends string = string, - TTypesMeta extends TypegenConstraint = TypegenDisabled -> = InternalMachineImplementations< - TContext, - ResolveTypegenMeta ->; +export type InternalMachineImplementations = { + actions?: MachineImplementationsActions; + actors?: MachineImplementationsActors; + delays?: MachineImplementationsDelays; + guards?: MachineImplementationsGuards; +}; type InitialContext< TContext extends MachineContext, @@ -1538,8 +1347,7 @@ export type MachineConfig< TInput = any, TOutput = unknown, TEmitted extends EventObject = EventObject, - TMeta extends MetaObject = MetaObject, - TTypesMeta = TypegenDisabled + TMeta extends MetaObject = MetaObject > = (Omit< StateNodeConfig< DoNotInfer, @@ -1608,8 +1416,7 @@ export interface MachineTypes< TInput, TOutput, TEmitted extends EventObject, - TMeta extends MetaObject, - TTypesMeta = TypegenDisabled + TMeta extends MetaObject > extends SetupTypes< TContext, TEvent, @@ -1626,7 +1433,6 @@ export interface MachineTypes< actions?: TAction; guards?: TGuard; delays?: TDelay; - typegen?: TTypesMeta; meta?: TMeta; } @@ -2230,8 +2036,7 @@ export type ActorRefFrom = ReturnTypeOrValue extends infer R infer _TInput, infer TOutput, infer TEmitted, - infer TMeta, - infer _TResolvedTypesMeta + infer TMeta > ? ActorRef< MachineSnapshot< @@ -2279,8 +2084,7 @@ export type InterpreterFrom< infer TInput, infer TOutput, infer TEmitted, - infer TMeta, - infer _TResolvedTypesMeta + infer TMeta > ? Actor< ActorLogic< @@ -2302,51 +2106,36 @@ export type InterpreterFrom< : never; export type MachineImplementationsFrom< - T extends AnyStateMachine | ((...args: any[]) => AnyStateMachine), - TRequireMissingImplementations extends boolean = false + T extends AnyStateMachine | ((...args: any[]) => AnyStateMachine) > = ReturnTypeOrValue extends StateMachine< infer TContext, - infer _TEvent, + infer TEvent, infer _TChildren, - infer _TActor, - infer _TAction, - infer _TGuard, - infer _TDelay, + infer TActor, + infer TAction, + infer TGuard, + infer TDelay, infer _TStateValue, - infer _TTag, + infer TTag, infer _TInput, infer _TOutput, - infer _TEmitted, - infer _TMeta, - infer TResolvedTypesMeta + infer TEmitted, + infer _TMeta > ? InternalMachineImplementations< - TContext, - TResolvedTypesMeta, - TRequireMissingImplementations + ResolvedStateMachineTypes< + TContext, + TEvent, + TActor, + TAction, + TGuard, + TDelay, + TTag, + TEmitted + > > : never; -// only meant to be used internally for debugging purposes -export type __ResolvedTypesMetaFrom = T extends StateMachine< - any, // context - any, // event - any, // children - any, // actor - any, // action - any, // guard - any, // delay - any, // state value - any, // tag - any, // input - any, // output - any, // emitted - any, // TMeta - infer TResolvedTypesMeta -> - ? TResolvedTypesMeta - : never; - export interface ActorScope< TSnapshot extends Snapshot, TEvent extends EventObject, @@ -2539,8 +2328,7 @@ type ResolveEventType = ReturnTypeOrValue extends infer R infer _TInput, infer _TOutput, infer _TEmitted, - infer _TMeta, - infer _TResolvedTypesMeta + infer _TMeta > ? TEvent : R extends MachineSnapshot< @@ -2578,8 +2366,7 @@ export type ContextFrom = ReturnTypeOrValue extends infer R infer _TInput, infer _TOutput, infer _TEmitted, - infer _TMeta, - infer _TResolvedTypesMeta + infer _TMeta > ? TContext : R extends MachineSnapshot< @@ -2606,7 +2393,7 @@ export type ContextFrom = ReturnTypeOrValue extends infer R infer _TOutput, infer _TEmitted, infer _TMeta, - infer _TResolvedTypesMeta + infer _TTypes > ? TContext : never @@ -2671,3 +2458,43 @@ export type ToChildren = export type StateSchema = { states?: Record; }; + +export interface StateMachineTypes { + context: MachineContext; + events: EventObject; + actors: ProvidedActor; + actions: ParameterizedObject; + guards: ParameterizedObject; + delays: string; + tags: string; + emitted: EventObject; +} + +/** + * @deprecated + */ +export interface ResolvedStateMachineTypes< + TContext extends MachineContext, + TEvent extends EventObject, + TActor extends ProvidedActor, + TAction extends ParameterizedObject, + TGuard extends ParameterizedObject, + TDelay extends string, + TTag extends string, + TEmitted extends EventObject = EventObject +> { + context: TContext; + events: TEvent; + actors: TActor; + actions: TAction; + guards: TGuard; + delays: TDelay; + tags: TTag; + emitted: TEmitted; +} + +export type GetConcreteByKey< + T, + TKey extends keyof T, + TValue extends T[TKey] +> = T & Record; diff --git a/packages/core/test/typeHelpers.test.ts b/packages/core/test/typeHelpers.test.ts index 32fda65a18..84c7754176 100644 --- a/packages/core/test/typeHelpers.test.ts +++ b/packages/core/test/typeHelpers.test.ts @@ -12,7 +12,6 @@ import { createActor, createMachine } from '../src/index.ts'; -import { TypegenMeta } from '../src/typegenTypes'; describe('ContextFrom', () => { it('should return context of a machine', () => { @@ -39,32 +38,6 @@ describe('ContextFrom', () => { // @ts-expect-error acceptMachineContext(obj); }); - - it('should return context of a typegened machine', () => { - const machine = createMachine({ - types: { - typegen: {} as TypegenMeta, - context: {} as { counter: number } - }, - context: { - counter: 0 - } - }); - - type MachineContext = ContextFrom; - - const acceptMachineContext = (_event: MachineContext) => {}; - - acceptMachineContext({ counter: 100 }); - acceptMachineContext({ - counter: 100, - // @ts-expect-error - other: 'unknown' - }); - const obj = { completely: 'invalid' }; - // @ts-expect-error - acceptMachineContext(obj); - }); }); describe('EventFrom', () => { @@ -91,30 +64,6 @@ describe('EventFrom', () => { }); }); - it('should return events for a typegened machine', () => { - const machine = createMachine({ - types: { - typegen: {} as TypegenMeta, - events: {} as - | { type: 'UPDATE_NAME'; value: string } - | { type: 'UPDATE_AGE'; value: number } - | { type: 'ANOTHER_EVENT' } - } - }); - - type MachineEvent = EventFrom; - - const acceptMachineEvent = (_event: MachineEvent) => {}; - - acceptMachineEvent({ type: 'UPDATE_NAME', value: 'test' }); - acceptMachineEvent({ type: 'UPDATE_AGE', value: 12 }); - acceptMachineEvent({ type: 'ANOTHER_EVENT' }); - acceptMachineEvent({ - // @ts-expect-error - type: 'UNKNOWN_EVENT' - }); - }); - it('should return events for an interpreter', () => { const machine = createMachine({ types: { @@ -142,7 +91,7 @@ describe('EventFrom', () => { }); describe('MachineImplementationsFrom', () => { - it('should return implementations for a typegen-less machine', () => { + it('should return implementations for a machine', () => { const machine = createMachine({ context: { count: 100 @@ -185,126 +134,10 @@ describe('MachineImplementationsFrom', () => { // @ts-expect-error acceptMachineImplementations(100); }); - - it('should return optional implementations for a typegen-based machine by default', () => { - interface TypesMeta extends TypegenMeta { - missingImplementations: { - actions: 'myAction'; - delays: never; - guards: never; - actors: never; - }; - eventsCausingActions: { - myAction: 'FOO'; - }; - } - const machine = createMachine({ - context: { - count: 100 - }, - types: { - typegen: {} as TypesMeta, - events: {} as { type: 'FOO' } | { type: 'BAR'; value: string } - } - }); - - const acceptMachineImplementations = ( - _options: MachineImplementationsFrom - ) => {}; - - acceptMachineImplementations({ - actions: { - // @ts-expect-error - foo: () => {} - } - }); - acceptMachineImplementations({ - actions: {} - }); - acceptMachineImplementations({ - actions: { - myAction: assign(({ context, event }) => { - ((_accept: number) => {})(context.count); - ((_accept: 'FOO') => {})(event.type); - return {}; - }) - } - }); - // @ts-expect-error - acceptMachineImplementations(100); - }); - - it('should return required implementations for a typegen-based machine with a flag', () => { - interface TypesMeta extends TypegenMeta { - missingImplementations: { - actions: 'myAction'; - delays: never; - guards: never; - actors: never; - }; - eventsCausingActions: { - myAction: 'FOO'; - }; - } - const machine = createMachine({ - context: { - count: 100 - }, - types: { - typegen: {} as TypesMeta, - events: {} as { type: 'FOO' } | { type: 'BAR'; value: string } - } - }); - - const acceptMachineImplementations = ( - _options: MachineImplementationsFrom - ) => {}; - - acceptMachineImplementations({ - actions: { - // @ts-expect-error - foo: () => {} - } - }); - acceptMachineImplementations({ - // @ts-expect-error - actions: {} - }); - acceptMachineImplementations({ - actions: { - myAction: assign(({ context, event }) => { - ((_accept: number) => {})(context.count); - ((_accept: 'FOO') => {})(event.type); - return {}; - }) - } - }); - // @ts-expect-error - acceptMachineImplementations(100); - }); }); describe('StateValueFrom', () => { - it('should return possible state values from a typegened machine', () => { - interface TypesMeta extends TypegenMeta { - matchesStates: 'a' | 'b' | 'c'; - } - - const machine = createMachine({ - types: { - typegen: {} as TypesMeta - } - }); - - function matches(_value: StateValueFrom) {} - - matches('a'); - matches('b'); - // @ts-expect-error - matches('unknown'); - }); - - it('should return any from a typegenless machine', () => { + it('should return any from a machine', () => { const machine = createMachine({}); function matches(_value: StateValueFrom) {} @@ -376,28 +209,7 @@ describe('ActorRefFrom', () => { }); describe('tags', () => { - it('derives tags from StateMachine when typegen is enabled', () => { - interface TypesMeta extends TypegenMeta { - tags: 'a' | 'b' | 'c'; - } - const machine = createMachine({ - types: { - typegen: {} as TypesMeta - } - }); - - type Tags = TagsFrom; - - const acceptTag = (_tag: Tags) => {}; - - acceptTag('a'); - acceptTag('b'); - acceptTag('c'); - // @ts-expect-error d is not a valid tag - acceptTag('d'); - }); - - it('derives string from StateMachine without typegen', () => { + it('derives string from StateMachine', () => { const machine = createMachine({}); type Tags = TagsFrom; diff --git a/packages/core/test/typegenTypes.test.ts b/packages/core/test/typegenTypes.test.ts deleted file mode 100644 index c836004e33..0000000000 --- a/packages/core/test/typegenTypes.test.ts +++ /dev/null @@ -1,1072 +0,0 @@ -import { fromCallback, fromPromise } from '../src/actors/index.ts'; -import { PromiseActorLogic } from '../src/actors/promise.ts'; -import { createMachine } from '../src/createMachine.ts'; -import { - assign, - createActor, - MachineContext, - StateMachine -} from '../src/index.ts'; -import { TypegenMeta } from '../src/typegenTypes.ts'; - -describe('typegen types', () => { - it('should limit event type provided to an action', () => { - interface TypesMeta extends TypegenMeta { - missingImplementations: { - actions: never; - delays: never; - guards: never; - actors: never; - }; - eventsCausingActions: { - myAction: 'FOO' | 'BAR'; - }; - } - - createMachine( - { - context: { foo: 100 }, - types: { - typegen: {} as TypesMeta, - events: {} as { type: 'FOO' } | { type: 'BAR' } | { type: 'BAZ' } - } - }, - { - actions: { - myAction: ({ event }) => { - event.type === 'FOO'; - event.type === 'BAR'; - // @ts-expect-error - event.type === 'BAZ'; - } - } - } - ); - }); - - it('should limit event type provided to a delay', () => { - interface TypesMeta extends TypegenMeta { - missingImplementations: { - actions: never; - delays: never; - guards: never; - actors: never; - }; - eventsCausingDelays: { - myDelay: 'FOO' | 'BAR'; - }; - } - - createMachine( - { - context: { foo: 100 }, - types: { - typegen: {} as TypesMeta, - events: {} as { type: 'FOO' } | { type: 'BAR' } | { type: 'BAZ' } - } - }, - { - delays: { - myDelay: ({ event }) => { - event.type === 'FOO'; - event.type === 'BAR'; - // @ts-expect-error - event.type === 'BAZ'; - - return 42; - } - } - } - ); - }); - - it('should limit event type provided to a guard', () => { - interface TypesMeta extends TypegenMeta { - missingImplementations: { - actions: never; - delays: never; - guards: never; - actors: never; - }; - eventsCausingGuards: { - myGuard: 'FOO' | 'BAR'; - }; - } - - createMachine( - { - context: { foo: 100 }, - types: { - typegen: {} as TypesMeta, - events: {} as { type: 'FOO' } | { type: 'BAR' } | { type: 'BAZ' } - } - }, - { - guards: { - myGuard: ({ event }) => { - event.type === 'FOO'; - event.type === 'BAR'; - // @ts-expect-error - event.type === 'BAZ'; - - return true; - } - } - } - ); - }); - - it('should not allow an unknown action', () => { - interface TypesMeta extends TypegenMeta { - missingImplementations: { - actions: never; - delays: never; - guards: never; - actors: never; - }; - eventsCausingActions: { - myAction: 'FOO' | 'BAR'; - }; - } - - createMachine( - { - context: { foo: 100 }, - types: { - typegen: {} as TypesMeta, - events: {} as { type: 'FOO' } | { type: 'BAR' } | { type: 'BAZ' } - } - }, - { - actions: { - // @ts-expect-error - unknownAction: () => {} - } - } - ); - }); - - it('should not allow an unknown delay', () => { - interface TypesMeta extends TypegenMeta { - missingImplementations: { - actions: never; - delays: never; - guards: never; - actors: never; - }; - eventsCausingDelays: { - myDelay: 'FOO' | 'BAR'; - }; - } - - createMachine( - { - context: { foo: 100 }, - types: { - typegen: {} as TypesMeta, - events: {} as { type: 'FOO' } | { type: 'BAR' } | { type: 'BAZ' } - } - }, - { - delays: { - // @ts-expect-error - unknownDelay: () => 42 - } - } - ); - }); - - it('should not allow an unknown guard', () => { - interface TypesMeta extends TypegenMeta { - missingImplementations: { - actions: never; - delays: never; - guards: never; - actors: never; - }; - eventsCausingGuards: { - myGuard: 'FOO' | 'BAR'; - }; - } - - createMachine( - { - context: { foo: 100 }, - types: { - typegen: {} as TypesMeta, - events: {} as { type: 'FOO' } | { type: 'BAR' } | { type: 'BAZ' } - } - }, - { - guards: { - // @ts-expect-error - unknownGuard: () => true - } - } - ); - }); - - it('should not allow an unknown actor', () => { - interface TypesMeta extends TypegenMeta { - missingImplementations: { - actions: never; - delays: never; - guards: never; - actors: never; - }; - eventsCausingActors: { - myActor: 'FOO' | 'BAR'; - }; - } - - createMachine( - { - context: { foo: 100 }, - types: { - typegen: {} as TypesMeta, - events: {} as { type: 'FOO' } | { type: 'BAR' } | { type: 'BAZ' } - } - }, - { - actors: { - // @ts-expect-error - unknownActor: () => () => {} - } - } - ); - }); - - it('should allow valid string `matches`', () => { - interface TypesMeta extends TypegenMeta { - matchesStates: 'a' | 'b' | 'c'; - missingImplementations: { - actions: never; - delays: never; - guards: never; - actors: never; - }; - } - - const machine = createMachine({ - context: { foo: 100 }, - types: { - typegen: {} as TypesMeta, - events: {} as { type: 'FOO' } | { type: 'BAR' } | { type: 'BAZ' } - }, - initial: 'a', - states: { - a: {} - } - }); - - createActor(machine).getSnapshot().matches('a'); - }); - - it('should allow valid object `matches`', () => { - interface TypesMeta extends TypegenMeta { - matchesStates: 'a' | { a: 'b' } | { a: 'c' }; - missingImplementations: { - actions: never; - delays: never; - guards: never; - actors: never; - }; - } - - const machine = createMachine({ - types: { typegen: {} as TypesMeta }, - context: { foo: 100 }, - initial: 'a', - states: { - a: {} - } - }); - - createActor(machine).getSnapshot().matches({ a: 'c' }); - }); - - it('should not allow invalid string `matches`', () => { - interface TypesMeta extends TypegenMeta { - matchesStates: 'a' | 'b' | 'c'; - missingImplementations: { - actions: never; - actors: never; - delays: never; - guards: never; - }; - } - - const machine = createMachine({ - context: { foo: 100 }, - types: { - typegen: {} as TypesMeta, - events: {} as { type: 'FOO' } | { type: 'BAR' } | { type: 'BAZ' } - }, - initial: 'a', - states: { - a: {} - } - }); - - createActor(machine).getSnapshot().matches( - // @ts-expect-error - 'd' - ); - }); - - it('should not allow invalid object `matches`', () => { - interface TypesMeta extends TypegenMeta { - matchesStates: 'a' | { a: 'b' } | { a: 'c' }; - missingImplementations: { - actions: never; - actors: never; - delays: never; - guards: never; - }; - } - - const machine = createMachine({ - types: { typegen: {} as TypesMeta }, - context: { foo: 100 }, - initial: 'a', - states: { - a: {} - } - }); - - createActor(machine).getSnapshot().matches({ - // @ts-expect-error - a: 'd' - }); - }); - - it('should allow a valid tag with `hasTag`', () => { - interface TypesMeta extends TypegenMeta { - tags: 'a' | 'b' | 'c'; - missingImplementations: { - actions: never; - delays: never; - guards: never; - actors: never; - }; - } - - const machine = createMachine({ - context: { foo: 100 }, - types: { - typegen: {} as TypesMeta, - events: {} as { type: 'FOO' } | { type: 'BAR' } | { type: 'BAZ' } - }, - initial: 'a', - states: { - a: {} - } - }); - - createActor(machine).getSnapshot().hasTag('a'); - }); - - it('should not allow an invalid tag with `hasTag`', () => { - interface TypesMeta extends TypegenMeta { - tags: 'a' | 'b' | 'c'; - missingImplementations: { - actions: never; - delays: never; - guards: never; - actors: never; - }; - } - - const machine = createMachine({ - context: { foo: 100 }, - types: { - typegen: {} as TypesMeta, - events: {} as { type: 'FOO' } | { type: 'BAR' } | { type: 'BAZ' } - }, - initial: 'a', - states: { - a: {} - } - }); - - createActor(machine).getSnapshot().hasTag( - // @ts-expect-error - 'd' - ); - }); - - it('should include init event in the provided parameter type if necessary', () => { - interface TypesMeta extends TypegenMeta { - eventsCausingActions: { - myAction: 'xstate.init'; - }; - internalEvents: { - 'xstate.init': { type: 'xstate.init' }; - }; - } - - createMachine( - { - types: { - typegen: {} as TypesMeta, - events: {} as { type: 'FOO' } | { type: 'BAR' } - } - }, - { - actions: { - myAction: ({ event }) => { - event.type === 'xstate.init'; - } - } - } - ); - }); - - it('should include generated dynamic internal event in the provided parameter if types.actors is not provided', () => { - interface TypesMeta extends TypegenMeta { - eventsCausingActions: { - myAction: 'xstate.done.actor.myActor' | 'FOO'; - }; - internalEvents: { - 'xstate.done.actor.myActor': { - type: 'xstate.done.actor.myActor'; - output: unknown; - __tip: 'Declare the type.'; - }; - }; - invokeSrcNameMap: { - myActor: 'xstate.done.actor.myActor'; - }; - } - - createMachine( - { - types: { - typegen: {} as TypesMeta, - events: {} as { type: 'FOO' } | { type: 'BAR' } - } - }, - { - actions: { - myAction: ({ event }) => { - if (event.type === 'FOO') { - return; - } - event.type === 'xstate.done.actor.myActor'; - event.output; - // indirectly check that it's not any - // @ts-expect-error - ((_accept: string) => {})(event.output); - } - } - } - ); - }); - - it('should use an event generated based on types.actors for a dynamic internal event over the generated fallback', () => { - interface TypesMeta extends TypegenMeta { - eventsCausingActions: { - myAction: 'xstate.done.actor.myActor' | 'FOO'; - }; - internalEvents: { - 'xstate.done.actor.myActor': { - type: 'xstate.done.actor.myActor'; - output: unknown; - __tip: 'Declare the type.'; - }; - }; - invokeSrcNameMap: { - myActor: 'xstate.done.actor.myActor'; - }; - } - - createMachine( - { - types: { - typegen: {} as TypesMeta, - events: {} as { type: 'FOO' } | { type: 'BAR' }, - actors: {} as { - src: 'callThing'; - logic: PromiseActorLogic; - id: 'myActor'; - } - } - }, - { - actions: { - myAction: ({ event }) => { - if (event.type === 'FOO') { - return; - } - event.type === 'xstate.done.actor.myActor'; - event.output; - ((_accept: string) => {})(event.output); - } - } - } - ); - }); - - it('should allow a promise actor returning the explicitly declared data in the given types.actors', () => { - interface TypesMeta extends TypegenMeta { - eventsCausingActors: { - myActor: 'FOO'; - }; - internalEvents: { - 'xstate.done.actor.myActor': { - type: 'xstate.done.actor.myActor'; - output: unknown; - __tip: 'Declare the type.'; - }; - }; - invokeSrcNameMap: { - myActor: 'xstate.done.actor.myActor'; - }; - } - - const child = fromPromise(() => Promise.resolve('foo')); - - createMachine( - { - types: { - typegen: {} as TypesMeta, - events: {} as { type: 'FOO' }, - actors: {} as { - src: 'myActor'; - logic: typeof child; - } - } - }, - { - actors: { - myActor: child - } - } - ); - }); - - it('should not allow a promise actor returning a different type than the explicitly declared one in the given types.actors', () => { - interface TypesMeta extends TypegenMeta { - eventsCausingActors: { - myActor: 'FOO'; - }; - internalEvents: { - 'xstate.done.actor.myActor': { - type: 'xstate.done.actor.myActor'; - output: unknown; - __tip: 'Declare the type.'; - }; - }; - invokeSrcNameMap: { - myActor: 'xstate.done.actor.myActor'; - }; - } - - createMachine( - { - types: { - typegen: {} as TypesMeta, - events: {} as { type: 'FOO' }, - actors: {} as { - src: 'myActor'; - logic: PromiseActorLogic; - } - } - }, - { - actors: { - // @ts-expect-error - myActor: fromPromise(() => Promise.resolve(42)) - } - } - ); - }); - - it('should allow a machine actor returning the explicitly declared output in the given types.actors', () => { - interface TypesMeta extends TypegenMeta { - eventsCausingActors: { - myActor: 'FOO'; - }; - internalEvents: { - 'xstate.done.actor.myActor': { - type: 'xstate.done.actor.myActor'; - output: unknown; - __tip: 'Declare the type.'; - }; - }; - invokeSrcNameMap: { - myActor: 'xstate.done.actor.myActor'; - }; - } - - const child = createMachine({ - types: {} as { - context: { foo: string }; - }, - context: { - foo: 'foo' - } - }); - - createMachine( - { - types: { - typegen: {} as TypesMeta, - events: {} as { type: 'FOO' }, - actors: {} as { - src: 'myActor'; - logic: typeof child; - } - } - }, - { - actors: { - myActor: child - } - } - ); - }); - - // it('should not allow a machine actor returning a different type than the explicitly declared one in the given types.actors', () => { - // interface TypesMeta extends TypegenMeta { - // eventsCausingActors: { - // myActor: 'FOO'; - // }; - // internalEvents: { - // 'xstate.done.actor.myActor': { - // type: 'xstate.done.actor.myActor'; - // output: unknown; - // __tip: 'Declare the type.'; - // }; - // }; - // invokeSrcNameMap: { - // myActor: 'xstate.done.actor.myActor'; - // }; - // } - - // createMachine( - // { - // tsTypes: {} as TypesMeta, - // schema: { - // events: {} as { type: 'FOO' }, - // actors: { - // myActor: { - // output: {} as { foo: string } - // } - // } - // } - // }, - // { - // actors: { - // // @ts-expect-error - // myActor: () => (createMachine<{ foo: number }>({})) - // } - // } - // ); - // }); - - it('should infer an action object with narrowed event type', () => { - interface TypesMeta extends TypegenMeta { - eventsCausingActions: { - actionName: 'BAR'; - }; - } - - createMachine( - { - types: { - typegen: {} as TypesMeta, - events: {} as { type: 'FOO' } | { type: 'BAR'; value: string } - } - }, - { - actions: { - actionName: assign(({ event }) => { - ((_accept: 'BAR') => {})(event.type); - return {}; - }) - } - } - ); - }); - - it('should accept a machine as an actor', () => { - interface TypesMeta extends TypegenMeta { - eventsCausingActors: { - fooActor: 'FOO'; - }; - } - - createMachine( - { - types: { - typegen: {} as TypesMeta, - events: {} as { type: 'FOO' } | { type: 'BAR'; value: string } - } - }, - { - actors: { - fooActor: createMachine({}) - } - } - ); - }); - - // it('should be able to send all of the parent event types back to the parent from an invoked callback', () => { - // interface TypesMeta extends TypegenMeta { - // eventsCausingActors: { - // fooActor: 'FOO'; - // }; - // } - - // createMachine( - // { - // tsTypes: {} as TypesMeta, - // schema: { - // events: {} as { type: 'FOO' } | { type: 'BAR' } - // } - // }, - // { - // actors: { - // fooActor: () => fromCallback(({ sendBack }) => { - // ((_accept: 'FOO') => {})(event.type); - - // sendBack({ type: 'BAR' }); - // sendBack({ type: 'FOO' }); - // // @ts-expect-error - // sendBack({ type: 'BAZ' }); - // }) - // } - // } - // ); - // }); - - it("should not provide a loose type for `receive`'s argument as a default", () => { - interface TypesMeta extends TypegenMeta { - eventsCausingActors: { - fooActor: 'FOO'; - }; - } - - createMachine( - { - types: { - typegen: {} as TypesMeta, - events: {} as { type: 'FOO' } | { type: 'BAR' } - } - }, - { - actors: { - fooActor: fromCallback(({ receive }) => { - receive((event) => { - ((_accept: string) => {})(event.type); - // @ts-expect-error TODO: determine how to get parent event type here - event.unknown; - }); - }) - } - } - ); - }); - - it("should allow specifying `receive`'s argument type manually", () => { - interface TypesMeta extends TypegenMeta { - eventsCausingActors: { - fooActor: 'FOO'; - }; - } - - createMachine( - { - types: { - typegen: {} as TypesMeta, - events: {} as { type: 'FOO' } | { type: 'BAR' } - } - }, - { - actors: { - fooActor: fromCallback(({ receive }) => { - receive((_event: { type: 'TEST' }) => {}); - // @ts-expect-error - receive((_event: { type: number }) => {}); - }) - } - } - ); - }); - - // it('should error correctly for implementations called in response to internal events when there is no explicit event type', () => { - // interface TypesMeta extends TypegenMeta { - // eventsCausingActions: { - // myAction: 'xstate.done.actor.invocation'; - // }; - // eventsCausingActors: { - // myInvocation: 'xstate.init'; - // }; - // internalEvents: { - // 'xstate.init': { type: 'xstate.init' }; - // }; - // invokeSrcNameMap: { - // myInvocation: 'xstate.done.actor.invocation'; - // }; - // } - - // createMachine( - // { - // tsTypes: {} as TypesMeta, - // schema: { - // actors: { - // myInvocation: {} as { - // data: string; - // } - // } - // } - // }, - // { - // actors: { - // // @ts-expect-error - // myInvocation: invokePromise(() => { - // return Promise.resolve(1); - // }) - // }, - // actions: { - // myAction: (_context, event) => { - // ((_accept: 'xstate.done.actor.invocation') => {})(event.type); - // ((_accept: string) => {})(event.output); - // // @ts-expect-error - // ((_accept: number) => {})(event.output); - // } - // } - // } - // ); - // }); - - it("shouldn't end up with `any` context after calling `state.matches`", () => { - interface TypesMeta extends TypegenMeta { - matchesStates: 'a' | 'b' | 'c'; - missingImplementations: { - actions: never; - delays: never; - guards: never; - actors: never; - }; - } - - const machine = createMachine({ - types: { - typegen: {} as TypesMeta, - context: {} as { - foo: string; - } - }, - context: { - foo: 'bar' - } - }); - - const state = createActor(machine).getSnapshot(); - - if (state.matches('a')) { - // @ts-expect-error - state.context.val; - } - }); - - it("shouldn't end up with `never` within a branch after two `state.matches` calls", () => { - interface TypesMeta extends TypegenMeta { - matchesStates: 'a' | 'a.b' | { a?: 'b' }; - missingImplementations: { - actions: never; - delays: never; - guards: never; - actors: never; - }; - } - - const machine = createMachine({ - types: { - typegen: {} as TypesMeta, - context: {} as { - foo: string; - } - }, - context: { - foo: 'bar' - } - }); - - const state = createActor(machine).getSnapshot(); - - if (state.matches('a') && state.matches({ a: 'b' })) { - ((_accept: string) => {})(state.context.foo); - } - }); - - it('should be possible to pass typegen-less machines to functions expecting a machine argument that do not utilize the typegen information', () => { - const machine = createMachine({}); - - function acceptMachine< - TContext extends MachineContext, - TEvent extends { type: string } - >( - machine: StateMachine< - TContext, - TEvent, - any, - any, - any, - any, - any, - any, - any, - any, - any, - any, // TMeta - any - > - ) { - return machine; - } - - acceptMachine(machine); - }); - - it('should error on a provided action where there are no inferred actions', () => { - interface TypesMeta extends TypegenMeta { - eventsCausingActions: never; - } - - createMachine( - { - types: { - typegen: {} as TypesMeta, - context: {} as { - foo: string; - } - }, - context: { - foo: 'bar' - } - }, - { - // @ts-expect-error - actions: { - testAction: () => {} - } - } - ); - }); - - it('should error on a provided delay where there are no inferred delays', () => { - interface TypesMeta extends TypegenMeta { - eventsCausingDelays: never; - } - - createMachine( - { - types: { - typegen: {} as TypesMeta, - context: {} as { - foo: string; - } - }, - context: { - foo: 'bar' - } - }, - { - // @ts-expect-error - delays: { - testDelay: () => {} - } - } - ); - }); - - it('should error on a provided guard where there are no inferred guards', () => { - interface TypesMeta extends TypegenMeta { - eventsCausingGuards: never; - } - - createMachine( - { - types: { - typegen: {} as TypesMeta, - context: {} as { - foo: string; - } - }, - context: { - foo: 'bar' - } - }, - { - // @ts-expect-error - guards: { - testGuard: () => {} - } - } - ); - }); - - it('should error on a provided actor where there are no events leading to it its invocation', () => { - interface TypesMeta extends TypegenMeta { - eventsCausingActors: never; - invokeSrcNameMap: never; - } - - createMachine( - { - types: { - typegen: {} as TypesMeta, - context: {} as { - foo: string; - } - }, - context: { - foo: 'bar' - } - }, - { - // TODO: determine the exact behavior here and how eventsCausingActors + TActor should interact with each other - // @x-ts-expect-error - actors: { - testActor: fromPromise(() => Promise.resolve(42)) - } - } - ); - }); - - it('should be able to provide events that use string unions as their type', () => { - interface TypesMeta extends TypegenMeta { - eventsCausingActions: { - increment: 'INC'; - decrement: 'DEC'; - }; - } - - createMachine( - { - types: { - typegen: {} as TypesMeta, - context: {} as { - count: number; - }, - events: {} as { type: 'INC' | 'DEC'; value: number } - }, - context: { - count: 0 - } - }, - { - actions: { - increment: assign(({ context, event }) => { - return { - count: context.count + event.value - }; - }) - } - } - ); - }); -}); diff --git a/packages/xstate-immer/test/typegenTypes.test.ts b/packages/xstate-immer/test/typegenTypes.test.ts deleted file mode 100644 index db0939d648..0000000000 --- a/packages/xstate-immer/test/typegenTypes.test.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { createMachine, TypegenMeta } from 'xstate'; -import { assign } from '../src'; - -describe('@xstate/immer', () => { - it('should infer an action object with narrowed event type', () => { - interface TypesMeta extends TypegenMeta { - eventsCausingActions: { - doSomething: 'update'; - }; - } - - createMachine( - { - context: { - count: 0 - }, - types: { - typegen: {} as TypesMeta, - context: {} as { count: number }, - events: {} as - | { - type: 'TOGGLE'; - } - | { - type: 'update'; - data: { count: number }; - } - } - }, - { - actions: { - doSomething: assign(({ context, event }) => { - ((_accept: 'update') => {})(event.type); - // no error - context.count += event.data.count; - // @ts-expect-error - ((_accept: "test that this isn't any") => {})(event); - // @ts-expect-error - ((_accept: "test that this isn't any") => {})(event.data); - }) - } - } - ); - }); -}); diff --git a/packages/xstate-react/test/typegenTypes.test.tsx b/packages/xstate-react/test/typegenTypes.test.tsx deleted file mode 100644 index 6d813ea3c2..0000000000 --- a/packages/xstate-react/test/typegenTypes.test.tsx +++ /dev/null @@ -1,94 +0,0 @@ -import { render } from '@testing-library/react'; -import { ActorRefFrom, assign, createMachine, TypegenMeta } from 'xstate'; -import { createActorContext, useActorRef, useMachine } from '../src/index.ts'; - -describe('useActorRef', () => { - it('should handle multiple state.matches when passed TypegenMeta', () => { - interface TypesMeta extends TypegenMeta { - matchesStates: 'a' | 'b'; - missingImplementations: { - actions: never; - actors: never; - guards: never; - delays: never; - }; - } - - const machine = createMachine({ - types: { typegen: {} as TypesMeta } - }); - - () => { - const [state] = useMachine(machine, {}); - if (state.matches('a')) { - return
a
; - } - - // matches should still be defined - if (state.matches('b')) { - return
b
; - } - }; - }); - - it('should handle multiple state.matches when NOT passed TypegenMeta', () => { - const machine = createMachine({}); - - () => { - const [state] = useMachine(machine, {}); - if (state.matches('a')) { - return
a
; - } - - // matches should still be defined - if (state.matches('b')) { - return
b
; - } - }; - }); -}); - -describe('createActorContext', () => { - it('should provide subset of the event type to action objects given in the `options` argument', () => { - interface TypesMeta extends TypegenMeta { - missingImplementations: { - actions: never; - actors: never; - guards: never; - delays: never; - }; - eventsCausingActions: { - fooAction: 'FOO'; - }; - } - - const machine = createMachine({ - types: { - typegen: {} as TypesMeta, - events: {} as { type: 'FOO' } | { type: 'BAR' } - } - }); - - const Context = createActorContext(machine); - - function App() { - return ( - { - ((_accept: 'FOO') => {})(event.type); - // @ts-expect-error - ((_accept: "test that this isn't any") => {})(event.type); - }) - } - })} - > - {null} - - ); - } - - render(); - }); -});