XStateで型安全なStateを表現する例
examplesを見ても「state毎に別の型を定義する」というのを表現している例が見当たらない
数分docsを読んだ程度なのでもっと良い書き方があるかもしれない
tstype 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内で型エラーが頻出して面倒なことになる
tsexport 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',
value: [...context.state.value, event.item],
}) 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',
},
},
},
});