XStateで型安全なStateを表現する例
examplesを見ても「state毎に別の型を定義する」というのを表現している例が見当たらない 数分docsを読んだ程度なのでもっと良い書き方があるかもしれない
code:ts
type TodoState =
| { type: 'ACTIVE'; value: readonly Item[] }
| { type: 'INACTIVE'; value: readonly [] };
type TodoEvent =
| { type: 'ADD'; item: Item }
| { type: 'TOGGLE'; id: number }
| { type: 'DISABLE' }
| { type: 'ENABLE' };
type Item = {
id: number;
name: string;
completed: boolean;
};
↑Stateを2種類に分けている
↓の
contextの部分でstate:のように包む必要がある
そうすると毎度、...context.stateのようなものが必要になる
本当はでデフォルトでcontext: {type:..,value:..}と書けるべきである
だが、そうするとactions内で型エラーが頻出して面倒なことになる
code:ts
export const machine = createMachine({
initial: 'ACTIVE',
types: {} as {
events: TodoEvent;
context: { state: TodoState };
},
context: {
state: {
type: 'INACTIVE',
value: [],
},
},
states: {
ACTIVE: {
on: {
ADD: {
target: 'ACTIVE',
actions: assign({
state: ({ context, event }) =>
({
type: 'ACTIVE',
}) as const,
}),
},
TOGGLE: {
target: 'ACTIVE',
actions: assign({
state: ({ context, event }) =>
({
type: 'ACTIVE',
value: context.state.value.map(item =>
item.id === event.id
? { ...item, completed: !item.completed }
: item,
),
}) as const,
}),
},
DISABLE: {
target: 'INACTIVE',
actions: assign({
state: () => ({ type: 'INACTIVE', value: [], }) as const,
}),
},
},
},
INACTIVE: {
on: {
ENABLE: 'ACTIVE',
},
},
},
});