typescript-fsaしゅごい
なんでしゅごいのかは@m0aさんのこちらの記事が分かりやすいです。
FSAって何って方はこちら。
この記事はtypescript-fsaによって作られるactionについて説明します。
Actionを作る
actionを作るにはまずactionCreatorを作ります
import actionCreatorFactory from 'typescript-fsa'
const actionCreator = actionCreatorFacory()
ここからactionを定義していきます
// typeが'HogeAction'かつpayloadの型がstringなFSA
const hogeAction = actionCreator<string>('hogeAction')
hogeAction.type
// 'hogeAction'
hogeAction('a')
// { type: 'hogeAction', payload: 'a' }
// payloadには型チェックが入る
hogeAction(1)
// error TS2345: Argument of type '1' is not assignable to parameter of type 'string'.
// payload無し
const hugaAction = actionCreator<void>('hugaAction')
const piyoAction = actionCreator('piyoAction')
// error
const errorAction = actionCreator<Error>('errorAction')
errorAction(new Error('hoge'))
// {
// type: 'errorAction',
// payload: Error: hoge
// at /home/kc5m/src/localhost/kc5m/fsa-saga-sample/[eval].ts:1:13
// // 省略
// error: true // Error型を渡すと自動的に{error: true}が付与される(条件変更可)
// }
非同期用Actionを作る
typescript-fsaには非同期処理向けに非同期用Actionをいい感じに作ってくれるAPIも用意されています。
AsyncActionCreator(AAC)と呼称されています。
実際にAACを定義してみます。
// AAC定義
const hogeAsyncAction = actionCreator.async<string, number, Error>('hogeAsyncAction')
actionCreator.async()はParams, Result, Error(javascriptのError型とは別)の3つの型からstarted, done, failedの3つのAction(FSA)を生成します。
上記の例で言うとstringがParams, numberがResult, ErrorがErrorに相当します。
生成された3つのActionは非同期処理での利用を想定されています。例えば以下の非同期関数があったとします。
const f = async (params: string): Promise<number> {
const result = await someAsyncFunc(pars)
if (!result) {
throw new Error('error')
}
return 0
}
startedはf()が実行されたタイミングを、doneはreturnされたタイミングを、そしてfailedはthrowされたタイミングをそれぞれ表現していると考えると分かりやすいかも知れません。
さて、このAACですが通常のActionではないのでそのままActionとして使えません。
hogeAsyncAction('aaa')
// error TS2349: This expression is not callable.
そのためAAC内propertyに生成されたActionを使う必要があります。
// started
hogeAsyncAction.started('a')
// { type: 'hogeAsyncAction_STARTED', payload: 'a' }
startedと同じようにdoneとfailedを使うとerrorが出ます。
// done
hogeAsyhogeAsyncAction.done(2)
// error TS2345: Argument of type '2' is not assignable to parameter of type '{ params: string; } & { result: number; }'.
// failed
hogeAsyhogeAsyncAction.failed(new Error('hoge'))
// error TS2345: Argument of type 'Error' is not assignable to parameter of type '{ params: string; } & { error: Error; }'.
AACが作るdone, failedのpayloadの型は拡張されていて、payloadの中にstartedに渡したpayloadが含まれるようになっています。
上記の例で言うとerrorにも書かれていますがdoneは{ params: string } & { result: number }型に、failedは{ params: string } & { error: Error }型になります。
hogeAsyncAction.done({ params: 'a', result: 1 })
// { type: 'hogeAsyncAction_DONE', payload: { params: 'a', result: 1 }}
hogeAsyncAction.failed({ params: 'a', error: new Error('aaa') })
// {
// type: 'hogeAsyncAction_FAILED',
// payload: {
// error: Error: aaa
// at /home/kc5m/src/localhost/kc5m/fsa-saga-sample/[eval].ts:1:33
// // 省略
// params: 'a'
// },
// error: true
// }
まとめると以下のようなります。
actionCreator.async<Params, Result, Error>()で作られるactionのpayloadの型は
-
started:Params -
done:{ params: Params } & { result: Result } -
failed:{ params: Params } & { error: Error }
また、doneはResultにError型(new Error()とか)が来てもerror: trueになりません。FAILEDはErrorにError型以外が来てもerror: trueになります。
const fugaAsyncAction = actionCreator.async<string, Error, string>('fugaAsyncAction')
fugaAsyncAction.done({result: new Error('aaa'), params: 'a'})
// {
// type: 'fugaAsyncAction_DONE',
// payload: {
// result: Error: aaa
// at /home/kc5m/src/localhost/kc5m/fsa-saga-sample/[eval].ts:1:32
// // 省略
// params: 'a'
// }
// }
fugaAsyncAction.failed({error: 'a', params: 'a'})
// {
// type: 'fugaAsyncAction_FAILED',
// payload: { error: 'a', params: 'a' },
// error: true
// }
最後に
typescript-fsaを使うことによって、型チェックが走るFSAの定義及び非同期処理用に複数のFSAを少ない行数で定義できます。
これ単体だけでも便利ですが、同じ作者より提供されている以下のCompanion Packagesを併用することにより更に便利に使うことができます(リンク省略)。
typescript-fsa-redux-sagatypescript-fsa-redux-observabletypescript-fsa-redux-thunktypescript-fsa-reducers
以上 ![]()