import BaseDuck , { DuckOptions } from "./BaseDuck" ; import Duck , { COMBINE_REDUCERS } from "./Duck" ; import { combineReducers } from "redux" ; import { fork } from "redux-saga/effects" ; import { parallel } from "redux-saga-catch" ; type DuckType < T extends BaseDuck > = { new ( options ? ) : T ; } ; type DUCKS_REDUCERS < T extends Record < string , BaseDuck > > = { [ key in keyof T ] : T [ key ] extends BaseDuck ? T [ key ] [ "reducer" ] : never ; } ; type DUCKS < T extends Record < string , DuckType < BaseDuck > > > = { [ key in keyof T ] : InstanceType < T [ key ] > ; } ; /**
 * 支持组合多个子Duck（`ducks`）的Duck，同时它自身也支持`reducers`，
 * 但需注意相同`route`下，`ducks`会覆盖`reducers`的状态
 *
 * Duck support compose multi sub duck(`ducks`), also support `reducers`,
 * but reminder with same `route`, `ducks` will override `reducers`'s state.
 */ export default class ComposableDuck extends Duck { protected get _disallowInheritGetters ( ) { return [ ... super . _disallowInheritGetters , "ducks" ] ; } protected get _cacheGetters ( ) { return [ ... super . _cacheGetters , "ducks" ] ; } protected getSubDuckOptions ( route ) { const { namespace , route : parentRoute } = this . options ; const parentSelector = this . selector ; return { namespace , route : parentRoute ? `${ parentRoute }/${ route }` : route , selector : state => parentSelector ( state ) [ route ] } ; } param ducks protected makeDucks < T extends Record < string , DuckType < BaseDuck > > > ( ducks ) { const map = { } as DUCKS < T > ; for ( const route of Object . keys ( ducks ) ) { let Duck = ducks [ route ] ; map [ route as keyof T ] = new Duck ( this . getSubDuckOptions ( route ) ) as any ; } return map ; } example get ducks ( ) : DUCKS < this [ "quickDucks" ] > & this [ "rawDucks" ] { return Object . assign ( { } , this . makeDucks < this [ "quickDucks" ] > ( this . quickDucks ) , this . rawDucks ) ; } example get quickDucks ( ) { return { } ; } example get rawDucks ( ) { return { } ; } get reducer ( ) : COMBINE_REDUCERS < this [ "reducers" ] & DUCKS_REDUCERS < this [ "ducks" ] > > { const ducksReducers = { } ; for ( const key of Object . keys ( this . ducks ) ) { ducksReducers [ key ] = this . ducks [ key ] . reducer ; } return combineReducers ( { ... this . reducers , ... ducksReducers } ) ; } private * ducksSaga ( ) { const { ducks } = this ; let sagas = [ ] ; for ( const key of Object . keys ( ducks ) ) { const duck = ducks [ key ] ; sagas = sagas . concat ( duck . sagas ) ; } yield parallel ( sagas ) ; } * saga ( ) { yield * super . saga ( ) ; yield fork ( [ this , this . ducksSaga ] ) ; } }