Coder Social home page Coder Social logo

piotrwitek / react-redux-typescript-guide Goto Github PK

View Code? Open in Web Editor NEW
13.3K 217.0 1.1K 2.87 MB

The complete guide to static typing in "React & Redux" apps using TypeScript

Home Page: https://piotrwitek.github.io/react-redux-typescript-guide/

License: MIT License

TypeScript 87.81% HTML 3.09% Shell 0.45% JavaScript 6.61% CSS 2.05%
react redux typescript patterns guidelines flow static-typing style-guide guide

react-redux-typescript-guide's People

Contributors

amitdahan avatar arshadkazmi42 avatar awestbro avatar binoy14 avatar chawax avatar chillitom avatar chodorowicz avatar emp823 avatar flymason avatar gulderov avatar incerta avatar ivankoleda avatar jakeboone02 avatar jeongukjae avatar kazup01 avatar kvoncode avatar levi-rocha avatar lordi avatar louisrli avatar mathiassoeholm avatar mleg avatar peterblazejewicz avatar piotrwitek avatar rubysolo avatar schrer avatar sckelemen avatar seeergo avatar sosukesuzuki avatar stradler42 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

react-redux-typescript-guide's Issues

add info about imports in module declaration

when creating 3rd party modules declarations imports should be put inside, otherwise it will be treated as augmentation and show error
Example:

declare module "react-custom-scrollbars" {
    import * as React from "react";

    export interface positionValues {
    ...

Interface better than type alias.

original:

type Props = {
  className?: string,
  style?: React.CSSProperties,
};

better:

interface Props = {
  className?: string,
  style?: React.CSSProperties,
}

what do you say?

[Section] Scalable Application Structure

Add a new section about how to create a scalable structure of your application.
This section should focus on goals:

  • files grouped by features
  • easy to add/remove features
  • enable/disable feature on demand
  • features should be reusable and pluggable across different redux applications

Better Typing for Component Callback Props

Hey there,

great guide! You recommend here to type the callbacks as () => any that did the trick for me and lead me to a better typed alternative since you know the actual type of the action creators:
typeof actionCreator.

import * as React from 'react';
import { connect } from 'react-redux';
import { RootState } from '@src/redux';
import { actionCreator } from '@src/redux/actions';

interface ReduxProps {
    action: typeof actionCreator; // <- instead of: action: () => any;
}

interface Props {
    label: string;
}

interface State {
    value: string;
}

class YourComp extends React.Component<Props & ReduxProps, State> {
    public componentWillMount() {
        this.props.action();
    }

    public render() {
        // render
    }
}

function mapStateToProps(state: RootState, props: Props): Props {
    return { ...props };
}

export default connect(mapStateToProps, { action: actionCreator })(YourComp); // <- Compiler will not complain

This at least works in TypeScript 2.8 so I hope that can help to refine your guide!

Best
Vinni

root action

I am confused how to create the root action properly.

From docs:

// example reducer
export const reducer: Reducer<State> = (state = 0, action: RootAction) => {
// root actions
export type RootAction =
  | ReactRouterAction
  | CountersActions[keyof CountersActions]
  | TodosActions[keyof TodosActions]
  | ToastsActions[keyof ToastsActions];
// example action creators
import { createAction, getType } from 'react-redux-typescript';

// Action Creators
export const actionCreators = {
  incrementCounter: createAction('INCREMENT_COUNTER'),
  showNotification: createAction('SHOW_NOTIFICATION', 
    (message: string, severity: Severity = 'default') => ({
      type: 'SHOW_NOTIFICATION', payload: { message, severity },
    })
  ),
};

CountersActions[keyof CountersActions] is equal to action creator types, not action types.
Should I define both action creator and actions separately?
Also ToastsActions[keyof ToastsActions]; doesn't work, but typeof ToastsActions[keyof typeof ToastsActions]; works.

[Section] Modelling async data with ADT

Add a new section with patterns on how to model data structures using static-typing to make the incorrect state unrepresentable. This should prevent a lot of edge cases and various display bugs by constraining our data structure to only represent correct state and also require our UI components to always handle all possible representable states when implementing a view components for the particular piece of data.

Rough sketch for this pattern:

Instead of modelling your remote data in reducer like this:

type State = {
  readonly isFetching: boolean,
  readonly error: string | null,
  readonly users: Array<User>,
};

Do it like this:

// we will use a generic union type, that can be designed specifically for our application needs
// it will set common conventions in reducers but also the way of handling different states of the components
// when fetching remote data
type RemoteData<E, D> =
  | { status: 'INITIAL' }
  | { status: 'LOADING' }
  | { status: 'ERROR', error: E }
  | { status: 'SUCCESS', data: D };

// declare your state as simple as that
type State = RemoteData<Error, Array<User>>

Now implement your component like this:

type Props = {
  usersModel: RemoteData<Error, Array<User>>,
};

const ViewComponent: React.SFC<Props> = ({ usersModel }) => {
  if (usersModel.status === 'INITIAL') {
    return null;
  } else if (usersModel.status === 'LOADING') {
    return <div>Loading...</div>;
  } else if (usersModel.status === 'ERROR') {
    return <div>An error has occurred { usersModel.error }</div>;
  }

  return (
    <>
      { usersModel.data.map(user => { ... }) }
    </>
  );
}

connect((state: State) => {
  usersModel: usersModelSelector(state),
})(ViewComponent);

connect stateful component

Is it expected that stateful components can't be connected to redux?
Example

// component

export interface LayoutProps {
  user?: User;
  logout: () => any;
}
type State = {
  isOpen: boolean;
};

class Layout extends React.PureComponent<LayoutProps, State> {
}

// container

const mapState = (state: State) => ({
  user: state.global.user
});
connect(mapState, {logout})(Layout);

error:

 Type 'typeof Layout' provides no match for the signature '(props: { user: User; } & { logout: (() => { type: "global/LOGOUT"; }) & TypeGetter<"global/LOGOUT">; } & { children?: ReactNode; }, context?: any): ReactElement<any>'.

It works if there are no actions

Here is my workaround

export default Layout as any as React.SFC<LayoutProps>;

Any thoughts? All libraries are the latest version.

Maybe have some mistake on combineReducers?

Thank you very much for your guide, but there are some puzzles in my practice.
This guide:

import { combineReducers } from 'redux';
import { routerReducer, RouterState } from 'react-router-redux';

import { countersReducer, CountersState } from '@src/redux/counters';
import { todosReducer, TodosState } from '@src/redux/todos';

interface StoreEnhancerState { }

export interface RootState extends StoreEnhancerState {
  router: RouterState;
  counters: CountersState;
  todos: TodosState;
}

import { RootAction } from '@src/redux';
export const rootReducer = combineReducers<RootState, RootAction>({
  router: routerReducer,
  counters: countersReducer,
  todos: todosReducer,
});

combineReducers Generic with two arguments in the above example.
But in my practice ,i find combineReducers don't need two variables.
So i check the declaration file of redux.

export function combineReducers<S>(reducers: ReducersMapObject): Reducer<S>;

This means that only one parameter is required.
Please confirm this questionใ€‚If it is wrong, please fix itใ€‚

My redux version๏ผš3.7.2

Reducer typing with redux-thunk

I've got some actions

export const setOrder = createAction('SET_ORDER', (order, id) => ({
    type: 'SET_ORDER',
    order,
    id,
}));

export const load = (id:string):ThunkAction<Promise<void>, any, void> => {
    return async (dispatch, getState):Promise<void> => {
        let result;
        try {
            result = await request(`/orders/${id}`);
            dispatch(setOrder(result, id));
        } catch (err) {
            console.error(err);
        }
    };
};

I create reducer as tutorial says:

import { getType } from 'typesafe-actions';
import { setOrder } from '../actions/order';

export type OrderState = {
    readonly loaded:string | null,
    readonly order:{}, // @TODO correct type
}

const initialState:OrderState = {
    loaded: null,
    order: {},
};

const orders = (state = initialState, action: OrdersAction) => {
    switch (action.type) {
        case getType(setOrder): {
            return {
                ...state,
                order: action.order,
                loaded: action.id,
            };
        }
        default: {
            return state;
        }
    }
};

export default orders;

import { $call } from 'utility-types';
import * as actions from '../actions/order';
const returnsOfActions = Object.values(actions).map($call);
export type OrdersAction = typeof returnsOfActions[number];

The problem is that my action type looks like:

(parameter) action: {
    type: "SET_ORDER";
    order: any;
    id: any;
} | ((dispatch: any, getState: () => any, extraArgument: void) => Promise<void>)

Looks like i should not map all actions, but select them manually. Is there any way to avoid this boilerplate?

Misleading "with default props" section

The example shown there will not work the way we except it in JSX due to the fact that compiler uses the type of props in order to define types of attributes.

So, basically with the code given, the next code will fail:

<StatefulCounterWithDefault label="" />;
//                          ~~~~~~~~ Property 'initialCount' is missing in type '{ label: ""; }'.

There is an issue where defaultProps are being discussed

I'm not sure If that's a good idea to put the workaround I use there because it might be a bit too complicated for beginners:

export const User = class extends React.Component<PropsWithDefault, {}> {
    // ...
} as React.ComponentClass<Props>;

What do you think guys?

Type assertion on the whole action

Hi,

I read about the typesafe-actions here, and I asked the question in there, but thought maybe it wouldn't hurt if I ask it here too.

I think the library it is what I have been looking for to substantially reduce boilerplate code for actions and action creators; thank you!

Creating actions (using createAction) and switching on them (using getType) in the reducer works fine, but I was wondering if there's a way to do type checking for a method that expects a specific kind of action.

Example of my actions (I'm using lodash for values and map):

export enum ActionTypes {
  GetCameras = 'GET_CAMERAS',
  GetCamerasSuccss = 'GET_CAMERAS_SUCCESS',
}

export const cameraActions = {
  getCameras: createAction(ActionType.GetCameras, ( /*...*/ ) => ({
    type: ActionTypes.GetCameras,
    /* payload: ... */
  }),
  getCamerasSuccess: createActionTypes.GetCamerasSuccess, (/*...*/) => ({
    type: ActionTypes.GetCameras,
    /* payload: ... */
  }),
};

const returnsOfActions = _.map(_.values(actions), $call));
export type CameraAction = typeof returnsOfActions[number];

Maybe a good example would be a case where the reducer wants to call another method for a specific action type, for example, in my reducer:

export const reducer = (state = initialState, action: CameraAction) => {
  case getType(cameraActions.getCameras):
    return state; /* ... */
  case getType(cameraActions.getCamerasSuccess):
    return receiveCameras(state, action);
  default:
    return state;
};

Now, in my receiveCameras method, I want to make sure the second argument is of type cameraActions.getCamerasSuccess.

I can do something like this:

const receiveCameras = (state: CameraState, action: CameraAction) => {
  if (action.type !== getType(cameraActions.getCamerasSuccess)) {
    return;
  }
  
  // Now my action type is correct
}

I was wondering if I can specify the type when defining the parameter in the method to avoid doing that if check

Thank you

Can you provide an example for type checking JSX childrens?

microsoft/TypeScript#13618

Example: We create High-level component package with strong typed how the lower components designed to be.

type Avatar: () => JSX.Element;
interface ILoginProps {
    accounts: object;
    setFormType: Function;
    children: Avatar;
}
class Login extends React.Component<ILoginProps, ILoginState> {
    public static propTypes = {
        Avatar: React.PropTypes.func,
 }
public render(): JSX.Element {

 const { Avatar } = this.props
 return (<Avatar/>)
}

React ChildContextProvider

I've been struggling with contextTypes in React 16.2.0 and found this solution:

import * as React from 'react';
import * as PropTypes from 'prop-types';

interface ProviderChildContext {
  blah: string;
}

export class Provider extends React.Component<void, void>
  implements React.ChildContextProvider<ProviderChildContext> {

  static childContextTypes = {
    blah: PropTypes.string
  };

  getChildContext() {
    return {
      blah: 'foo'
    };
  }
}

Do you think that something like this could be also part of this guide?

Stateful component with connect

I'm using an older version of react-redux types (4.4.41) so apologies if this is incorrect. Also apologies if I've missed the example in this guide. I wanted a connected Stateful container. I appreciate that perhaps containers should be stateless as they are just there to wrap the stateful components. If this is your opinion then feel free to close this issue. Otherwise I thought it would be useful to share the typing I use:

import * as React from "react";
import {connect, Dispatch} from "react-redux";

import {AppState} from "../state/shape";
/**
* interface AppState {
*     someState: number;
* }
*/
import {saveItemAction} from "../actions/item";
/**
* export const saveItemAction = () => ({type: "SAVE_ITEM"})
*/

interface Props {
    normalProp: string;
}

interface PropsFromState {
    somePropFromState: number;
}

interface PropsFromDispatch {
    itemClicked: () => void;
}

interface AllProps extends Props, PropsFromState, PropsFromDispatch {}

class MyComponent extends React.Component<AllProps, {}> {

    render() {

        return (
        <div>
            <div>normalProp: {this.props.normalProp}</div>
            <div>somePropFromState: {this.props.somePropFromState}</div>
        </div>);
    }
}

const map_state_to_props = (state: AppState): PropsFromState => {
    return {
      somePropFromState: state.someState,
    };
};

const map_dispatch_to_props = (state: AppState, dispatch: Dispatch<AppState>): PropsFromDispatch => {
    return {
        itemClicked: () => dispatch(saveItemAction()),
    };
};

export const ConnectedMyComponent = connect(
    map_state_to_props,
    map_dispatch_to_props
)<Props>(MyComponent);

Incorrect action creator type when using bindActionCreators and redux-thunk

Specifically I have this action defined.

getTransitionForm: (params: GetTransitionFormParams) =>
    (dispatch: Dispatch<RootState>, getState: () => RootState, extraArgument: any) => 
         Promise<any>;

When mapped as follows as per your guide from section "Connected Container without OwnProps using Type Inference" https://github.com/piotrwitek/react-redux-typescript-guide#connected-container-with-ownprops

export const mapDispatchToProps = (dispatch: Dispatch<RootState>) =>
  bindActionCreators(
    {
      getTransitionForm,
    },
    dispatch
  );
const dispatchProps = returntypeof(mapDispatchToProps);

The resulting value of dispatchProps is

const dispatchProps: {
    getTransitionForm: (params: GetTransitionFormParams) =>
        (dispatch: Dispatch<RootState>, getState: () => RootState, extraArgument: any) => 
             Promise<any>;
}

I believe after binding it should be.

const dispatchProps: {
    getTransitionForm: (params: GetTransitionFormParams) => Promise<any>;
}

Which I expect is not going to be easy to derive.
I only discovered this as I wanted to do something with the returned promise.
Thanks for your great guide.

actions in redux connect

The component has following props:

// MyComponent.tsx
export interface MyComponentProps {
  foo: () => any,
  bar: (n: number) => any,
}


const MyComponent: React.SFC<MyComponentProps> = (props) => {
.....
};

The container

// MyComponentContainer.ts
const mapState = (state: State) => ({
  ...
});

export default connect(mapState, {
  foo: actions.foo,
  bar: actions.bar,
})(MyComponent);

Few observations:

  1. If the action is missing then it doesn't report any error
    example: connect(mapState, {})(MyComponent); // no ts error

  2. If there is an extra action then it reports an error
    example: connect(mapState, {extra: actions.extra})(MyComponent); // ts error

  3. Wrong signature (too many arguments).
    The component expects foo: () => any, but we connect (str: string) => any. No ts error.

  4. Wrong signature (missing arguments).
    The component expects bar: (n: number) => any, but we connect () => any. A ts error will be reported.

Is it possible that we receive TS compiler errors in all cases? Especially, 1. case would be useful.

Thanks

Suggestion: lower learning curve by including short tutorial

This is a great resource and it has helped me tremendously. Unfortunately it's hard to understand all the intricacies from the guide itself and I believe it would help a lot if there was a few step-by-step guides on for instance how to set up a small 1 or 2 component app, how to integrate each type of component and so on.

Type inference for reselect in containers

Hi,
when declaring my containers props i do something like this:

// In my selector file
const simpleSelector = (state: RootState): string => state.mydata;
const reselectSelector = createSelector([simpleSelector], (selector: string): string => selector);

// In my container file
interface SimpleContainerProps {
  simpleSelector: typeof simpleSelector; // this is ok because type is string
  reselectSelector: typeof reselectSelector; // this gives problems because type is  'OutputSelector<RootState, string, (selector: string) => string>'
}

This gives me the opportunity to be sure that if I change a selector used by any components on my app, typescript compiler will throw an error. However as you can see from my code's comments I cant use it for selectors created by reselect using createSelector.

Does anyone encountered this problem too?

Proposal

I think we may organize the code this way. You can paste in IDE (vscode e.g.) and try typing with autocompletion and typing error highlighting.
What do you think?

type ActionCreators<TActions> = { [ P in keyof TActions ]?: (() => TActions[P])|null };
type Reducer<TState,TActions> = { [ P in keyof TActions ]?: (s: TState, a: TActions[P]) => TState };

/// --------------------------

interface RootState {
	prop1: number;
}

interface Reducer1Actions {
	expandAll: null;
	expand: { id: number };
	update: { id: number, field: string; value: any }
}

// ----------

var actions = /*createActions()*/<ActionCreators<Reducer1Actions>>({
	expand: (id: number) => ({ id }),
	update: (id: number, field: string, value: any) => ({ id, field, value })
});

var reducer = /*createReducer()*/<Reducer<RootState, Reducer1Actions>>{
	expand(s, a) { // s and a are with autocompletion
		s.prop1 = a.id; 
		return s;
	},
	update(s, a) { // s and a are with autocompletion
		s[a.field] = a.value;
		return s;
	}
}

Add sample with @decorator usage

The tsconfig.json sample suggests usage of experimental decorator flag. So it would be nice to show @autobind decorator removing constructor bindings.

From this:

  counter: number = 10;

  constructor(props: {}) {
    super(props);
    this.handleIncrement = this.handleIncrement.bind(this);
  }
  handleIncrement() {
    alert(`Increment ${this.counter}`);
  }
  render() {
    return (
      <SFCCounter
        count={4}
        label="Click Me"
        onIncrement={this.handleIncrement}
      />
    );
  }

to this:

import autobind from 'autobind-decorator';
...
  counter: number = 10;
  @autobind
  handleIncrement() {
    alert(`Increment ${this.counter}`);
  }
  render() {
    return (
      <SFCCounter
        count={4}
        label="Click Me"
        onIncrement={this.handleIncrement}
      />
    );
  }

suggestion: add info about dispatched action types

When declaring a connected component's property types I find it helpful to use the typeof operator to declare dispatched function types so that the property matches the action's declaration:

const actions = {
  ping: createAction('ping/PING', (arg: number) => ({
    type: 'ping/PING',
    arg,
  })),
};

interface Props {
  ping: typeof actions.ping;
}

const PingTestComponent: React.SFC<Props> = ({ping}) => {
  return (
    <Button onPress={() => ping(123)} title="ping"/>
  );
};

export const PingTest = connect(
  null,
  ({ ping: actions.ping })
)(PingTestComponent);

Error With Typescript 2.7 in react-redux-typescript/es5-commonjs/mapped-types.d.ts

(11,92): error TS2344: Type '({ [P in keyof T]: P; } & {} & { [k: string]: never; })[keyof T]' does not satisfy the constraint 'keyof (Pick<T, ({ [P in keyof T]: P; } & { [P in keyof U]: never; } & { [k: string]: never; })[ke...'.
  Type '({ [P in keyof T]: P; } & {})[keyof T]' is not assignable to type 'keyof (Pick<T, ({ [P in keyof T]: P; } & { [P in keyof U]: never; } & { [k: string]: never; })[ke...'.
    Type '{ [P in keyof T]: P; }[keyof T]' is not assignable to type 'keyof (Pick<T, ({ [P in keyof T]: P; } & { [P in keyof U]: never; } & { [k: string]: never; })[ke...'.
      Type 'keyof T' is not assignable to type 'keyof (Pick<T, ({ [P in keyof T]: P; } & { [P in keyof U]: never; } & { [k: string]: never; })[ke...'.
        Type 'keyof T' is not assignable to type 'never'.
          Type '{ [P in keyof T]: P; }[keyof T]' is not assignable to type 'never'.
            Type '({ [P in keyof T]: P; } & {})[keyof T]' is not assignable to type 'never'.
              Type '({ [P in keyof T]: P; } & {} & { [k: string]: never; })[keyof T]' is not assignable to type 'never'.
                Type '({ [P in keyof T]: P; } & {})[keyof T]' is not assignable to type 'never'.
                  Type '{ [P in keyof T]: P; }[keyof T]' is not assignable to type 'never'.
                    Type 'keyof T' is not assignable to type 'never'.

Errors on these lines:

export declare type Overwrite<T extends object, U extends object> = Pick<(Diff<T, U> & U), OmitKeys<keyof T, never>>;
export declare type Assign<T extends object, U extends object> = Pick<(Diff<T, U> & U), OmitKeys<keyof (T & U), never>>;

Syntax error with $call and createAction

I am getting this TS compile error

./src/store/ducks/auth.module.ts
Syntax error: Unexpected token, expected ] (95:41)
//My actions
export const actions = {
  signup: createAction(types.SIGNUP_REQUEST, (email: string, password: string) => ({
    type: types.SIGNUP_REQUEST,
    payload: { email, password },
  })),
....

  93 | 
  94 | const returnsOfActions = _.values(actions).map($call);
> 95 | type AppAction = typeof returnsOfActions[number];

It seems to be mad about the [number] part. Any idea on what the issue is?

Tried to build and got errors

$ npm run build

[email protected] prebuild c:\projects\react-redux-typescript-guide\examples
rm -rf out

[email protected] build c:\projects\react-redux-typescript-guide\examples
tsc -p ./

1 import * as uuid from 'uuid';
~~~~

src/api/articles.ts(1,13): error TS6133: 'uuid' is declared but never used.

8 const articlesResponse = require('./fixtures/articles.json');
~~~~~~~~~~~~~~~~

src/api/articles.ts(8,7): error TS6133: 'articlesResponse' is declared but never used.

7 import { actionCreators } from '../modules/converter';
~~~~~~~~~~~~~~~~~~~~~~

src/components/connected-stateless-counter.tsx(7,32): error TS2307: Cannot find module '../modules/converter'.

14 counter: state.converter.counter,
~~~~~~~

src/components/connected-stateless-counter.tsx(14,28): error TS2339: Property 'counter' does not exist on type 'IState'.

24 const checkProps: IStatelessCounterProps = { ...stateProps, ...dispatchProps };
~~~~~~~~~~

src/components/connected-stateless-counter.tsx(24,7): error TS6133: 'checkProps' is declared but never used.

8
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

src/containers/home.tsx(8,32): error TS2322: Type '{ label: "ConnectedStatelessCounter"; }' is not assignable to type 'IntrinsicAttributes & IntrinsicClassAttributes<Component<IStatelessCounterProps, ComponentState>>...'.
Type '{ label: "ConnectedStatelessCounter"; }' is not assignable to type 'Readonly'.
Property 'counter' is missing in type '{ label: "ConnectedStatelessCounter"; }'.

Hall of Contributors

The Guide is growing strong and I would like to add a Hall of Contributors.
I'm looking for some simple solution that will generate contributors list from JSON, the result would be nice markdown/html table with heads and icons describing the kind of contribution.
If someone know such solution please share some links here. Thanks.

semantic error TS4023 Exported variable 'increment' has or is using name 'TypeGetter' from external module

I am facing this error while trying to build my redux store

semantic error TS4023 Exported variable 'increment' has or is using name 'TypeGetter' from external module

Here is my source code:-

actions.ts

import { createAction } from 'typesafe-actions'

export const increment = createAction('INCREMENT')
export const add = createAction('ADD', (amount: number) => ({
    type: 'ADD',
    payload: amount,
  }))

reducer.ts

import { getType } from 'typesafe-actions';
import { RootState, RootAction } from '@src/redux/store';

import { add } from './actions';

export type CounterState = {
    readonly value: number,
};

export const initialState: CounterState = {
    value: 0,
}; 

export const CounterReducer = (state: RootState, action: RootAction) => {
    switch (action.type) {
        case getType(add):
            return state.counters.value + action.payload;
        default:
            return state.counters.value
    }
} 

store.ts

import { createStore, Store, combineReducers } from 'redux';
import * as CounterActions from '@src/redux/actions';
import { CounterReducer, CounterState } from '@src/redux/reducer';
import { $call } from 'utility-types';

export const returnsOfActions = [
  ...Object.values(CounterActions)
].map($call);

export type AppAction = typeof returnsOfActions[number];

export type RootAction = 
  | AppAction


export interface StoreEnhancerState { }

export interface RootState extends StoreEnhancerState {
  counters: CounterState;
}

const rootReducer = combineReducers<RootState>({
    counters: CounterReducer
});

function configureStore(initialState?: RootState) {
  return createStore(
    rootReducer,
    initialState!
  );
}

const store: Store<RootState> = configureStore();

export { store };

On searching a bit about the error, I found out that if I add

import { TypeGetter } from 'typesafe-actions'
export { TypeGetter }

to actions.ts, I do not get the error.

Why is it so?

Update:

tsconfig.json

{
  "compilerOptions": {
    "target": "es5",                          
    "module": "commonjs", 
    "lib": [
      "dom",
      "es2016",
      "es2017.object"
    ],                  
    "jsx": "react",
    "declaration": false,
    "outDir": "./lib",
    "importHelpers": true,
    "strict": true,
    "noImplicitAny": true,
    "strictNullChecks": true,
    "strictFunctionTypes": true,
    "noImplicitThis": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "noEmitHelpers": true,         
    "noImplicitReturns": true,
    "noFallthroughCasesInSwitch": true,
    "moduleResolution": "node",
    "baseUrl": "./",
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true,
    "types": ["node"],
    "allowSyntheticDefaultImports": true,
    "forceConsistentCasingInFileNames": true
  }

suggestion: connected generic component

The repository already contains nice examples of generic components (generic-list) and connected components (sfc-counter-connected), but I'm having problems with the correct declaration and usage of connected generic components.

I would like to be able to write something like:
export const ConnectedListExtended<T> = connect<GenericListProps<T>, {}, OwnProps>(mapStateToProps)(GenericList<T>);

An example of the combination of these two examples would be really helpfull.

Thanks in advance!

@connect decorator

It'd be great to see how react+redux+typescript can use the @connect(..) decorator syntax to connect state/actions to a component's props.

Example of chained API requests via actions?

Hello Piotr,

This guide is excellent and think this guide/repo is very useful for writing clean react/redux/typescript code.

One issue I am running into (more likely just failing to wrap my head around this) is how to handle ajax chain of requests.

For example I have a few different actions defined such as registerUser, updateProfile separated in two reducers. Now each of these actions have a corresponding epic that does an ajax call to post some data and on success returns a new action registerUserSuccess or on failure registerUserFailure. Same with updateProfile where the ajax request returns updateProfileSuccess/Failure. This all works great when called individually. What if I have a case where in another flow I have the data to both registerUser and updateProfile in the same flow and want them to occur sequentially?

Do you have any suggestions for the best way to handle this/reuse code in this scenario? Is it best to make a new action/reducer/epic flow that handles just this case, or is it possible to re-use the existing actions and have them execute sequentially depending on the result of the ajax call?

In addition it might be useful to have an API Call middleware example in the guide that allows us to reuse logic when defining <SOME_TASK>REQUEST/SUCCESS/FAIL

[Enhancement] Add a nested HOCs example with connect

Issuehunt badges

You might consider writing up techniques for dealing with prop types on components with multiple nested HOCs. For example, I frequently have components with three layers of HOCs: React-Router, Redux, and Apollo-React (graphql client).

I have a handle on how to deal, but recent changes in both Typescript and various declarations have made these stricter and harder to get right. I'm not at all confident that my design pattern for this is the best, but I'll share if you've nothing.


IssueHunt Summary

piotrwitek piotrwitek has been rewarded.

Backers (Total: $50.00)

Submitted pull Requests


Tips


IssueHunt has been backed by the following sponsors. Become a sponsor

How to define OwnProps?

Can you provide an example how to define OwnProps? In below example, I was creating counter container from a purely react component. The react component takes following props.

React Component Props

export interface ICounterProps {
    label: string;
    counter: { value: number };
    isSaving: boolean;
    isLoading: boolean;
    error: string;
    increment: (n: number) => void;
    save: (n: number) => void;
    load: () => void;
}

interface State {

}

And in Container file

const mapStateToProps = (state: Store.All, OwnProps) => ({
  counter: state["@sample/counter"],
  isSaving: state["@sample/isSaving"],
  isLoading: state["@sample/isLoading"],
  error: state["@sample/error"],
})

const mapDispatchToProps = (dispatch: Function) => ({
  increment: (n: number) =>
    dispatch(incrementCounter(n)),
  load: () =>
    dispatch(loadCount(null)),
  save: (value: number) =>
    dispatch(saveCount({ value })),
})

const stateProps = returntypeof(mapStateToProps);
const dispatchProps = returntypeof(mapDispatchToProps);
type Props = typeof stateProps & typeof dispatchProps
type State = {}

export const Counter: React.ComponentClass<OwnProps> = connect(mapStateToProps, mapDispatchToProps)(CounterComponent)

In case the OwnProps should be label.

example of state merging in reducer not compliant with TS v2.4

Hi,

Thank you for the guide.

How would you recommend the example on "Spread operation with Exact Types check to guard against excess or mismatched props" be used with strictNullChecks? As a Partial makes all properties nullable, it is required to define all State in this form:

export type State = {
  readonly counter: number | undefined,
  readonly baseCurrency: string | undefined,
};

This is the same as effectively switching strictNullChecks off. Is there any other way?

Cheers.

SFCCounterConnectedExtended does not work in examples

The initialCount property does not work on the SFCCounterConnectedExtended component.

import * as React from 'react';

import { SFCCounterConnectedExtended } from '@src/connected';

export default () => (
  <SFCCounterConnectedExtended
    label={'SFCCounterConnectedExtended'}
    initialCount={10}
  />
);

the initalCount is not read into the props because you are using the SFCCounter. What would be your recommendation on fixing this, create a new component or interface ?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.