Best practices for writing well-typed code
createEvent# By default, this methos returns Event<void>.
Copy const event = createEvent ( )
event ( )
Event type can be defined as generic
Copy const event = createEvent < number > ( )
event ( 0 )
createEffect# Typescript can infer effect result type from given handler, but argument type should be defined either in handler argument or as generic type
Copy const sendMessageFx = createEffect ( async ( params : { text : string } ) => {
return 'ok'
} )
const sendWarningFx = createEffect < { warn : string } , string > ( async ( { warn } ) => {
return 'ok'
} )
createEffect and custom errors# When you need custom error types (Fail type in Effect) you can define all generics explicitly:
Copy const sendWarningFx = createEffect < { warn : string } , string , AxiosError > (
async ( { warn } ) => {
return 'ok'
} ,
)
In case when effect's handler is defined before effect itself you can allow typescript to infer type of Params and Done by using typeof handler in first generic and optionally provide Fail type as second one
Copy const sendMessage = async ( params : { text : string } ) => {
return 'ok'
}
const sendMessageFx = createEffect < typeof sendMessage , AxiosError > ( sendMessage )
event.prepend# To add types to events, created by event.prepend you need to add type either to prepend function argument or as generic type
Copy const message = createEvent < string > ( )
const userMessage = message . prepend ( ( { text } : { text : string } ) => text )
const warningMessage = message . prepend < { warn : string } > ( ( { warn } ) => warn )
attach# To allow typescript to infer types of created effect, add type to mapParams first argument, which will become effect params type
Copy const sendTextFx = createEffect < { text : string } , 'ok' > ( )
const sendWarningFx = attach ( {
effect : sendTextFx ,
mapParams : ( { warn } : { warn : string } ) => ( { text : warn } ) ,
} )
split# Typescript type predicates can be used to split common event type to several cases (hence the name)
Copy type UserMessage = { kind : 'user' ; text : string }
type WarnMessage = { kind : 'warn' ; warn : string }
const message = createEvent < UserMessage | WarnMessage > ( )
const { userMessage , warnMessage } = split ( message , {
userMessage : ( msg ) : msg is UserMessage => msg . kind === 'user' ,
warnMessage : ( msg ) : msg is WarnMessage => msg . kind === 'warn' ,
} )
guard# Typescript type predicates can be used to infer result type by filter function
Copy type UserMessage = { kind : 'user' ; text : string }
type WarnMessage = { kind : 'warn' ; warn : string }
const message = createEvent < UserMessage | WarnMessage > ( )
const userMessage = guard ( message , {
filter : ( msg ) : msg is UserMessage => msg . kind === 'user' ,
} )
createApi# To allow typescript to infer types of created events, add type to second argument of given reducers
Copy const $count = createStore ( 0 )
const { add , sub } = createApi ( $count , {
add : ( x , add : number ) => x + add ,
sub : ( x , sub : number ) => x - sub ,
} )
is methods can help to infer unit type (thereby is methods acts as TypeScript type guards ) which can help to write strongly-typed helper functions
Copy export function getUnitType ( unit : unknown ) {
if ( is . event ( unit ) ) {
return 'event'
}
if ( is . effect ( unit ) ) {
return 'effect'
}
if ( is . store ( unit ) ) {
return 'store'
}
}