Skip to content

Commit

Permalink
Improved .matches(value) inference for typestates containing union …
Browse files Browse the repository at this point in the history
…types as values
  • Loading branch information
Andarist committed Jan 20, 2021
1 parent 375bb6b commit af6b7c7
Show file tree
Hide file tree
Showing 3 changed files with 75 additions and 2 deletions.
5 changes: 5 additions & 0 deletions .changeset/breezy-beds-trade.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'xstate': patch
---

Improved `.matches(value)` inference for typestates containing union types as values.
6 changes: 5 additions & 1 deletion packages/core/src/State.ts
Original file line number Diff line number Diff line change
Expand Up @@ -291,7 +291,11 @@ export class State<
public matches<TSV extends TTypestate['value']>(
parentStateValue: TSV
): this is State<
(TTypestate extends { value: TSV } ? TTypestate : never)['context'],
(TTypestate extends any
? { value: TSV; context: any } extends TTypestate
? TTypestate
: never
: never)['context'],
TEvent,
TStateSchema,
TTypestate
Expand Down
66 changes: 65 additions & 1 deletion packages/core/test/match.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ import {
matchState,
matchesState,
Machine,
createMachine
createMachine,
assign
} from '../src';

describe('matchState()', () => {
Expand Down Expand Up @@ -375,4 +376,67 @@ describe('matches() method', () => {
expect(state).toBeTruthy();
}
});

it('should compile with a typestate value that is a union', (done) => {
interface MachineContext {
countObject:
| {
count: number;
}
| undefined;
}

type MachineEvent = { type: 'TOGGLE' };

type MachineTypestate =
| {
value: 'active' | { other: 'one' };
context: MachineContext & { countObject: { count: number } };
}
| {
value: 'inactive';
context: MachineContext;
};

const machine = createMachine<
MachineContext,
MachineEvent,
MachineTypestate
>({
initial: 'active',
context: {
countObject: { count: 0 }
},
states: {
inactive: {
entry: assign({
countObject: undefined
}),
on: { TOGGLE: 'active' }
},
active: {
entry: assign({
countObject: (ctx) => ({
count: (ctx.countObject?.count ?? 0) + 1
})
}),
on: { TOGGLE: 'other' }
},
other: {
on: { TOGGLE: 'active' },
initial: 'one',
states: {
one: {}
}
}
}
});

const state = machine.initialState;

if (state.matches('active')) {
expect(state.context.countObject.count).toBe(1);
done();
}
});
});

0 comments on commit af6b7c7

Please sign in to comment.