Last active
August 3, 2018 01:16
-
-
Save terrierscript/a70323b4d85e0fe1c33b228824979631 to your computer and use it in GitHub Desktop.
TypeScript + Reduxはもうぼちぼちサードライブラリに頼らなくてもある程度はいい感じに補完してくれる ref: https://qiita.com/terrierscript/items/b3f9dd95a4c7afe0b102
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import { | |
| createStore, | |
| Reducer, | |
| Action, | |
| combineReducers, | |
| ActionCreatorsMapObject, | |
| ReducersMapObject, | |
| ActionCreator | |
| } from "redux" | |
| //// State全体の定義 | |
| export type AppState = { | |
| counter: number | |
| } | |
| //// ActionとActionCreatorの定義 | |
| // type CounterAction = Action<"INCREMENT" | "DECREMENT"> でも可 | |
| type CounterActionType = "INCREMENT" | "DECREMENT" | |
| type CounterAction = Action<CounterActionType> | |
| // これだけだるいが利用側のために二重定義してる。後述 | |
| export interface CounterActionCreators | |
| extends ActionCreatorsMapObject<CounterAction> { | |
| increment: ActionCreator<CounterAction> | |
| decrement: ActionCreator<CounterAction> | |
| } | |
| export const counterActions: CounterActionCreators = { | |
| increment: () => { | |
| return { type: "INCREMENT" } | |
| }, | |
| decrement: () => { | |
| return { type: "DECREMENT" } | |
| } | |
| } | |
| //// Reducer。genericsらへんはちょっと怠けてる | |
| export const counterReducer: Reducer<any, CounterAction> = ( | |
| state = 0, | |
| action | |
| ) => { | |
| switch (action.type) { | |
| case "INCREMENT": // このへんVSCode補完効いて最高の気分 | |
| return state + 1 | |
| case "DECREMENT": | |
| return state - 1 | |
| } | |
| return state | |
| } | |
| export const generateStore = () => { | |
| const reducerMap: ReducersMapObject<AppState> = { | |
| counter: counterReducer | |
| } | |
| return createStore(combineReducers(reducerMap)) | |
| } | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // Counter sample | |
| import React, { Component } from "react" | |
| import { connect } from "react-redux" | |
| import { bindActionCreators, Dispatch } from "redux" | |
| import { | |
| counterActions, | |
| AppState, | |
| CounterActionCreators | |
| } from "../store" | |
| // State -> Propsに変換する例。 | |
| // 変換不要なら type StateProps = AppState でいいだろう | |
| type StateProps = { | |
| cnt: number | |
| } | |
| // 子のPropsはStatePropsとCounterActionCreatorsを持つ | |
| type ChildProps = StateProps & CounterActionCreators | |
| class CounterInner extends Component<ChildProps> { | |
| render() { | |
| return ( | |
| <div> | |
| <div>{this.props.cnt}</div> | |
| <button onClick={this.props.increment}>+</button> | |
| <button onClick={this.props.decrement}>-</button> | |
| </div> | |
| ) | |
| } | |
| } | |
| const connectCounter = connect( | |
| (state: AppState): StateProps => ({ | |
| cnt: state.counter | |
| }), | |
| (dispatch: Dispatch) => bindActionCreators(counterActions, dispatch) | |
| ) | |
| export const Counter = connectCounter(CounterInner) | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| type StateProps = { | |
| cnt: number | |
| } | |
| type ChildProps = StateProps & typeof counterActions | |
| class CounterInner extends Component<ChildProps> { | |
| render() { | |
| const { increment, decrement } = this.props | |
| return ( | |
| <div> | |
| <div>{this.props.cnt}</div> | |
| <button onClick={increment}>+</button> | |
| <button onClick={decrement}>-</button> | |
| </div> | |
| ) | |
| } | |
| } | |
| const connectCounter = connect( | |
| (state: AppState): StateProps => ({ | |
| cnt: state.counter | |
| }), | |
| (dispatch) => bindActionCreators(counterActions, dispatch) | |
| ) | |
| export const Counter = connectCounter(CounterInner) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // Extraの部分を作成する関数。Tuple in Rest parameter大活躍! | |
| type ExtraFunction<Arg extends any[], R> = (...args: Arg) => R | |
| type ActionCreator<Arg extends any[], Action> = (...args: Arg) => Action | |
| // 関数のoverload | |
| export function createAppAction<A extends string>( | |
| type: A | |
| ): ActionCreator<any[], AppAction<A>> | |
| export function createAppAction<A extends string, Arg extends any[], R>( | |
| type: A, | |
| fn: ExtraFunction<Arg, R> | |
| ): ActionCreator<Arg, AppAction<A, R>> | |
| export function createAppAction(type, extraFunction?) { | |
| return (...args) => { | |
| if (extraFunction) { | |
| const extra = extraFunction(...args) | |
| return { type, ...extra } | |
| } | |
| return { type } | |
| } | |
| } | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| const increment = createAppAction(ActionType.increment) | |
| const decrement = createAppAction(ActionType.decrement) | |
| const force = createAppAction(ActionType.force, (num: number) => { | |
| return { | |
| count: num | |
| } | |
| }) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // もとの定義 | |
| // type CounterAction = | |
| // | AppAction<ActionType.increment> | |
| // | AppAction<ActionType.decrement> | |
| // | AppAction<ActionType.force, { count: number }> | |
| type CounterAction = ReturnType< | |
| typeof increment | typeof decrement | typeof force | |
| > |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| export type AppActionCreators< | |
| T extends { [key: string]: (...args) => any } | |
| > = ReturnType<T[keyof T]> | |
| export const counterActions = { | |
| increment: createAppAction(ActionType.increment), | |
| decrement: createAppAction(ActionType.decrement), | |
| force: createAppAction(ActionType.force, (num: number) => { | |
| return { | |
| count: num | |
| } | |
| }) | |
| } | |
| type CounterAction = AppActionCreators<typeof counterActions> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import { Dispatch } from "redux" | |
| import { AppState } from "~/client/store/store" | |
| import { counterActions } from "~/client/store/counter" | |
| type StateProps = { | |
| cnt: number | |
| } | |
| type DispatchProps = { | |
| dispatch: Dispatch | |
| } | |
| type ChildProps = StateProps & DispatchProps | |
| class CounterInner extends Component<ChildProps> { | |
| render() { | |
| const { dispatch } = this.props | |
| const { increment, decrement } = counterActions | |
| return ( | |
| <div> | |
| <div>{this.props.cnt}</div> | |
| <button onClick={(e) => dispatch(increment())}>+</button> | |
| <button onClick={(e) => dispatch(decrement())}>-</button> | |
| </div> | |
| ) | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| const increment = (): CounterAction => { | |
| return { type: "INCREMENT" } | |
| } | |
| const decrement = (): CounterAction => { | |
| return { type: "DECREMENT" } | |
| } | |
| const force = (num: number): CounterAction => { // 引数をとる例 | |
| return { | |
| type: "FORCE", | |
| count: num | |
| } | |
| } | |
| // ここでまとめ直しが必要 | |
| export const counterActions = { increment, decrement, force } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // typeof counterActionsをしてる。ただしこのactionが引数を正しくは認識出来ない | |
| type ChildProps = StateProps & typeof counterActions | |
| class CounterInner extends Component<ChildProps> { | |
| render() { | |
| // 省略 | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // 元 | |
| // type CounterActionType = "INCREMENT" | "DECREMENT" | |
| // type CounterAction = Action<CounterActionType> | |
| type CounterAction = { | |
| type: "INCREMENT" | |
| } | { | |
| type: "DECREMENT" | |
| } | { | |
| type: "FORCE" | |
| count: number | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // Flux-standardなaction。typescript-fsaからほぼパクってきた | |
| interface AppAction<ActionName extends string, Payload = null> { | |
| type: ActionName | |
| payload?: Payload | |
| error?: boolean | |
| meta?: Object | |
| } | |
| type CounterAction = | |
| | AppAction<"INCREMENT"> | |
| | AppAction<"DECREMENT"> | |
| | AppAction<"FORCE", { count: number }> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import { Action } from "redux" | |
| // Actionに対して、Extraな値をMappedTypeにして追加する形で認識させたものを定義。AnyActionの改良版。 | |
| export type AppAction<T extends string, Extra extends {} = {}> = | |
| Action<T> & | |
| { [K in keyof Extra]: Extra[K] } | |
| type CounterAction = | |
| | AppAction<"INCREMENT"> | |
| | AppAction<"DECREMENT"> | |
| | AppAction<"FORCE", { count: number }> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| enum ActionType { | |
| increment = "INCREMENT", | |
| decrement = "DECREMENT", | |
| force = "FORCE" | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| export type AppAction<T extends string, Extra extends {} = {}> = | |
| Action<T> & | |
| { [K in keyof Extra]: Extra[K] } | |
| enum ActionType { | |
| increment = "INCREMENT", | |
| decrement = "DECREMENT", | |
| force = "FORCE" | |
| } | |
| type CounterAction = | |
| | AppAction<ActionType.increment> | |
| | AppAction<ActionType.decrement> | |
| | AppAction<ActionType.force, { count: number }> | |
| const increment = (): CounterAction => { | |
| return { type: ActionType.increment } | |
| } | |
| const decrement = (): CounterAction => { | |
| return { type: ActionType.decrement } | |
| } | |
| const force = (num: number): CounterAction => { | |
| return { | |
| type: ActionType.force, | |
| count: num | |
| } | |
| } | |
| export const counterActions = { increment, decrement, force } | |
| export const counterReducer: Reducer<number, CounterAction> = ( | |
| state = 0, | |
| action | |
| ) => { | |
| switch (action.type) { | |
| case ActionType.increment: | |
| return state + 1 | |
| case ActionType.decrement: | |
| return state - 1 | |
| case ActionType.force: | |
| return action.count | |
| } | |
| return state | |
| } | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment