├── .gitignore
├── README.md
├── index.tsx
└── package.json
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | package-lock.json
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Actually typing your React-Redux program
2 |
3 | A guide for those who are stuck not being able to migrate their apps away from JS/TypeScript/Flow. See [index.ts](./index.ts)
4 |
5 | Seriously though, just use anything else.
--------------------------------------------------------------------------------
/index.tsx:
--------------------------------------------------------------------------------
1 | // install @types/react-redux and other nonsense
2 |
3 | import * as React from "react";
4 | import { connect } from "react-redux";
5 |
6 | // import { YourActualAppState, YourActualAppDispatch } from './wherever-it-is.ts'
7 | type YourActualAppState = {
8 | whatever: {
9 | apple: String;
10 | banana: String;
11 | };
12 | };
13 | // hopefully you make a union of your actual actions in YourActualAppActions or something
14 | type YourActualAppDispatch = (action: { type: "ASDF" }) => void;
15 |
16 | // map state to props function that returns { whateverStateField: string }
17 | export function mapStateToProps({ whatever }: YourActualAppState) {
18 | return {
19 | whateverStateField: "whatever"
20 | };
21 | }
22 |
23 | // map dispatch to props function that returns { whateverDispatchField: (...) => void }
24 | export function mapDispatchToProps(dispatch: YourActualAppDispatch) {
25 | return {
26 | whateverDispatchField: (whatever: { kiwi: string }) =>
27 | dispatch({ type: "ASDF" })
28 | };
29 | }
30 |
31 | // function for making a "value" of the result type
32 | function makeExtractable(fn: (input: Input) => Output): Output {
33 | return (false as true) && fn({} as any); // trick compiler into evaluating return value, maybe this will be a feature in 4.0+++
34 | }
35 |
36 | // use makeExtractable on mapStateToProps
37 | const extractStateProps = makeExtractable(mapStateToProps);
38 | type StateProps = typeof extractStateProps;
39 | // on hover:
40 | // type StateProps = {
41 | // whateverStateField: string;
42 | // }
43 |
44 | // same with extractDispatchProps
45 | const extractDispatchProps = makeExtractable(mapDispatchToProps);
46 | type DispatchProps = typeof extractDispatchProps;
47 | // on hover:
48 | // type DispatchProps = {
49 | // whateverDispatchField: (whatever: { kiwi: string; }) => void;
50 | // }
51 |
52 | // whatever props this actually exposes
53 | export type Props = {
54 | whateverPropField: {
55 | pineapple: string;
56 | };
57 | };
58 |
59 | // Clean/Pick trick suggested by @gcanti for cleaner intersections
60 | type Clean = Pick;
61 | // intersection type for your component
62 | type Type = Clean;
63 | // so now:
64 | // type Type = {
65 | // whateverPropField: {
66 | // pineapple: string;
67 | // };
68 | // whateverStateField: string;
69 | // whateverDispatchField: (whatever: {
70 | // kiwi: string;
71 | // }) => void;|
72 | // }
73 |
74 | // OR
75 | // type Type = Props & StateProps & DispatchProps // intersection type for your component
76 | // type Type = Props & {
77 | // whateverStateField: string;
78 | // } & {
79 | // whateverDispatchField: (whatever: {
80 | // kiwi: string;
81 | // }) => void;
82 | // }
83 |
84 | // important: set Props for exporting the type
85 | export const YourComponent: React.ComponentClass = connect(
86 | mapStateToProps,
87 | mapDispatchToProps
88 | )(function(props: Type) { // Type used here for the combined props from connect
89 | return
90 | });
91 |
92 | // congrats, now you have something actually useful that type checks in your whole app, unlike most every example I've seen
93 | // remember: if you value your sanity, choose any compile-to-JS language that isn't Javascript/Typescript/Flow
94 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "bullshit",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "author": "",
10 | "license": "MIT",
11 | "dependencies": {
12 | "@types/react": "^16.0.23",
13 | "@types/react-redux": "^5.0.12",
14 | "@types/redux": "^3.6.0",
15 | "prettier": "^1.8.2",
16 | "react": "^16.1.1",
17 | "react-redux": "^5.0.6",
18 | "typescript": "^2.6.1"
19 | }
20 | }
21 |
--------------------------------------------------------------------------------