Skip to content

Commit

Permalink
Make required input required in createActor (#4704)
Browse files Browse the repository at this point in the history
* Make required `input` required in `createActor`

* fixed tests
  • Loading branch information
Andarist authored Jan 25, 2024
1 parent 0e5bf8d commit 78699ae
Show file tree
Hide file tree
Showing 5 changed files with 41 additions and 4 deletions.
5 changes: 5 additions & 0 deletions .changeset/curly-moons-trade.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'xstate': minor
---

`createActor` will now error if the required `input` is not given to it.
15 changes: 14 additions & 1 deletion packages/core/src/createActor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,11 @@ import { AnyActorSystem, Clock, createSystem } from './system.ts';
import type {
ActorScope,
AnyActorLogic,
ConditionalRequired,
DoneActorEvent,
EventFromLogic,
InputFrom,
IsNotNever,
Snapshot,
SnapshotFrom
} from './types.ts';
Expand Down Expand Up @@ -704,6 +707,9 @@ export class Actor<TLogic extends AnyActorLogic>
}
}

type RequiredOptions<TLogic extends AnyActorLogic> =
undefined extends InputFrom<TLogic> ? never : 'input';

/**
* Creates a new actor instance for the given actor logic with the provided options, if any.
*
Expand Down Expand Up @@ -738,7 +744,14 @@ export class Actor<TLogic extends AnyActorLogic>
*/
export function createActor<TLogic extends AnyActorLogic>(
logic: TLogic,
options?: ActorOptions<TLogic>
...[options]: ConditionalRequired<
[
options?: ActorOptions<TLogic> & {
[K in RequiredOptions<TLogic>]: unknown;
}
],
IsNotNever<RequiredOptions<TLogic>>
>
): Actor<TLogic> {
return new Actor(logic, options);
}
Expand Down
6 changes: 3 additions & 3 deletions packages/core/test/guards.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { createActor, createMachine, raise } from '../src/index.ts';
import { InputFrom, createActor, createMachine, raise } from '../src/index.ts';
import { and, not, or, stateIn } from '../src/guards';
import { trackEntries } from './utils.ts';

Expand Down Expand Up @@ -93,7 +93,7 @@ describe('guard conditions', () => {
});

it('should transition if condition based on event is met', () => {
const actorRef = createActor(lightMachine).start();
const actorRef = createActor(lightMachine, { input: {} }).start();
actorRef.send({
type: 'EMERGENCY',
isEmergency: true
Expand All @@ -102,7 +102,7 @@ describe('guard conditions', () => {
});

it('should not transition if condition based on event is not met', () => {
const actorRef = createActor(lightMachine).start();
const actorRef = createActor(lightMachine, { input: {} }).start();
actorRef.send({
type: 'EMERGENCY'
});
Expand Down
1 change: 1 addition & 0 deletions packages/core/test/input.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ describe('input', () => {
}
});

// @ts-expect-error
const snapshot = createActor(machine).getSnapshot();

expect(snapshot.status).toBe('error');
Expand Down
18 changes: 18 additions & 0 deletions packages/core/test/types.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { stopChild } from '../src/actions/stopChild';
import { PromiseActorLogic, fromCallback, fromPromise } from '../src/actors';
import {
ActorRefFrom,
InputFrom,
MachineContext,
ProvidedActor,
Spawner,
Expand Down Expand Up @@ -4339,3 +4340,20 @@ describe('self', () => {
});
});
});

describe('createActor', () => {
it(`should require input to be specified when it is required`, () => {
const logic = fromPromise(({}: { input: number }) => Promise.resolve(100));

// @ts-expect-error
createActor(logic);
});

it(`should not require input when it's optional`, () => {
const logic = fromPromise(({}: { input: number | undefined }) =>
Promise.resolve(100)
);

createActor(logic);
});
});

0 comments on commit 78699ae

Please sign in to comment.