{
32 | render() {
33 | const { actions, counter } = this.props;
34 |
35 | return (
36 |
37 |
38 | {counter}
39 |
40 |
41 | );
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/modules/counter/constants/ActionTypes.ts:
--------------------------------------------------------------------------------
1 | export const IncCounter = "IncCounter";
2 | export const DesCounter = "DecCounter";
3 | export const RstCounter = "RstCounter";
4 |
--------------------------------------------------------------------------------
/modules/counter/index.tsx:
--------------------------------------------------------------------------------
1 | export { CounterAppContainer } from "./components/CounterApp";
2 |
--------------------------------------------------------------------------------
/modules/counter/models/RootState.ts:
--------------------------------------------------------------------------------
1 | export interface RootState {
2 | counter?: number;
3 | }
4 |
--------------------------------------------------------------------------------
/modules/counter/models/index.ts:
--------------------------------------------------------------------------------
1 | export { RootState } from "./RootState";
2 |
--------------------------------------------------------------------------------
/modules/counter/reducers/RootReducer.ts:
--------------------------------------------------------------------------------
1 | import { Action } from "redux-actions";
2 | import { RootState } from "../models";
3 | import * as ActionType from "../constants/ActionTypes";
4 |
5 | export function RootReducer(state: RootState, action: Action): RootState {
6 | switch (action.type) {
7 | case ActionType.IncCounter:
8 | return { counter: state.counter + 1 };
9 | case ActionType.DesCounter:
10 | return { counter: state.counter - 1 };
11 | case ActionType.RstCounter:
12 | return { counter: 0 };
13 | }
14 |
15 | return state || { counter: 0 };
16 | }
17 |
--------------------------------------------------------------------------------
/modules/counter/stores/RootStore.ts:
--------------------------------------------------------------------------------
1 | import { RootReducer } from "../reducers/RootReducer";
2 | import { createStore } from "../../../helpers/createStore";
3 |
4 | export function configStore() {
5 |
6 | const store = createStore(RootReducer);
7 |
8 | // hot reloading
9 | if (typeof module !== "undefined" && module.hot) {
10 | module.hot.accept("../reducers/RootReducer", () => {
11 | store.replaceReducer(require("../reducers/RootReducer").RootReducer);
12 | });
13 | }
14 |
15 | return store;
16 | }
17 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-redux-typescript-start",
3 | "version": "0.1.0",
4 | "description": "A starter kit for react + redux + typescript",
5 | "main": "index.tsx",
6 | "scripts": {
7 | "init": "npm install && typings install --ambient",
8 | "dev": "node ./server/index.js",
9 | "build": "set NODE_ENV=production && webpack --config webpack/webpack.prod.js"
10 | },
11 | "keywords": [],
12 | "author": "techirdliu@gmail.com",
13 | "license": "ISC",
14 | "dependencies": {
15 | "babel": "^6.5.2",
16 | "babel-core": "^6.7.2",
17 | "babel-loader": "^6.2.4",
18 | "babel-plugin-react-transform": "^2.0.2",
19 | "babel-polyfill": "^6.7.2",
20 | "babel-preset-es2015": "^6.6.0",
21 | "babel-preset-react": "^6.5.0",
22 | "babel-preset-stage-0": "^6.5.0",
23 | "babel-runtime": "^6.6.1",
24 | "classnames": "^2.2.3",
25 | "express": "^4.13.4",
26 | "react": "^0.14.7",
27 | "react-addons-css-transition-group": "^0.14.7",
28 | "react-dom": "^0.14.7",
29 | "react-redux": "^4.4.1",
30 | "react-transform-catch-errors": "^1.0.2",
31 | "react-transform-hmr": "^1.0.4",
32 | "redbox-react": "^1.2.2",
33 | "redux": "^3.3.1",
34 | "redux-logger": "^2.6.1",
35 | "redux-thunk": "^2.0.1",
36 | "serve-index": "^1.7.3",
37 | "ts-loader": "^0.8.1",
38 | "ts-node": "^0.6.1",
39 | "typescript": "^1.8.7",
40 | "webpack": "^1.12.14",
41 | "webpack-dev-middleware": "^1.5.1",
42 | "webpack-dev-server": "^1.14.1",
43 | "webpack-hot-middleware": "^2.10.0"
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/server/index.js:
--------------------------------------------------------------------------------
1 | require("ts-node/register");
2 | var serve = require("./server.ts").serve;
3 |
4 | var port = process.env.port || 8081;
5 | serve(port);
6 |
--------------------------------------------------------------------------------
/server/server.ts:
--------------------------------------------------------------------------------
1 | import * as path from "path";
2 | import * as express from "express";
3 | import * as webpack from "webpack";
4 | import * as serveIndex from "serve-index";
5 |
6 | export function serve(port: number) {
7 | port = process.env.PORT || 8081
8 |
9 | var app = express();
10 |
11 | if (process.env.NODE_ENV !== "production") {
12 | setupWebpackDevelopmentServer(app);
13 | }
14 |
15 | const staticPath = path.resolve(__dirname, "../static");
16 | app.use(express.static(staticPath));
17 |
18 | app.listen(port, function (err) {
19 | if (err) {
20 | console.error(JSON.stringify(err));
21 | return;
22 | }
23 |
24 | console.log(`\nDevelopment server served at http://localhost:${port}\n\n`);
25 | });
26 |
27 | return app;
28 | }
29 |
30 | function setupWebpackDevelopmentServer(app: express.Express) {
31 | var config = require('../webpack/webpack.config');
32 | var compiler = webpack(config);
33 |
34 | var devMiddleware = require('webpack-dev-middleware')(compiler, {
35 | publicPath: config.output.publicPath,
36 | noInfo: true,
37 | stats: { colors: true },
38 | poll: true,
39 | quiet: false,
40 | reload: true
41 | });
42 |
43 | var hotMiddleware = require('webpack-hot-middleware')(compiler, { reload: true });
44 |
45 | app.use(devMiddleware);
46 | app.use(hotMiddleware);
47 | }
48 |
--------------------------------------------------------------------------------
/static/index.css:
--------------------------------------------------------------------------------
1 | button {
2 | width: 200px;
3 | height: 50px;
4 | }
5 | span {
6 | display: inline-block;
7 | padding: 20px;
8 | }
9 |
--------------------------------------------------------------------------------
/static/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Hello React + Redux + TypeScript
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "es6",
4 | "module": "commonjs",
5 | "moduleResolution": "node",
6 | "outDir": "./tsbuild",
7 | "isolatedModules": false,
8 | "jsx": "react",
9 | "experimentalDecorators": true,
10 | "emitDecoratorMetadata": true,
11 | "declaration": false,
12 | "noImplicitAny": false,
13 | "removeComments": true,
14 | "noLib": false,
15 | "preserveConstEnums": true
16 | },
17 | "exclude": [
18 | "node_modules",
19 | "typings/browser",
20 | "typings/browser.d.ts"
21 | ],
22 | "compileOnSave": false,
23 | "buildOnSave": false,
24 | "atom": {
25 | "rewriteTsconfig": false
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/typings.json:
--------------------------------------------------------------------------------
1 | {
2 | "globalDependencies": {
3 | "classnames": "registry:dt/classnames#0.0.0+20150923160543",
4 | "express": "registry:dt/express#4.0.0+20160218233549",
5 | "express-serve-static-core": "registry:dt/express-serve-static-core#0.0.0+20160218233549",
6 | "mime": "registry:dt/mime#0.0.0+20151204023458",
7 | "node": "registry:dt/node#4.0.0+20160311162451",
8 | "react": "registry:dt/react#0.14.0+20160314090524",
9 | "react-addons-css-transition-group": "registry:dt/react-addons-css-transition-group#0.14.0+20151118193746",
10 | "react-addons-transition-group": "registry:dt/react-addons-transition-group#0.14.0+20160106161637",
11 | "react-dom": "registry:dt/react-dom#0.14.0+20160314090524",
12 | "redux": "registry:dt/redux#1.0.0+20160201195450",
13 | "redux-actions": "registry:dt/redux-actions#0.8.0+20150915051529",
14 | "redux-logger": "registry:dt/redux-logger#2.6.0+20160226185156",
15 | "redux-thunk": "registry:dt/redux-thunk#2.0.1+20160308210923",
16 | "serve-index": "registry:dt/serve-index#1.7.2+20160105023018",
17 | "serve-static": "registry:dt/serve-static#0.0.0+20160218233549",
18 | "source-map": "registry:dt/source-map#0.0.0+20151201114758",
19 | "uglify-js": "registry:dt/uglify-js#2.6.1+20160106153543",
20 | "webpack": "registry:dt/webpack#1.12.9+20160125043835"
21 | },
22 | "dependencies": {
23 | "react-redux": "registry:npm/react-redux#4.4.0+20160207114942"
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/webpack/webpack.config.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | module.exports = process.env.NODE_ENV === "production"
4 | ? require("./webpack.prod.js")
5 | : require("./webpack.dev.js");
--------------------------------------------------------------------------------
/webpack/webpack.dev.js:
--------------------------------------------------------------------------------
1 | var webpack = require('webpack');
2 | var path = require("path");
3 |
4 | var commonEntry = ['webpack-hot-middleware/client?path=http://localhost:8081/__webpack_hmr', 'babel-polyfill'];
5 |
6 | module.exports = {
7 | devtool: 'sourcemap',
8 | debug: true,
9 | entry: {
10 | index: commonEntry.concat(['./index.tsx']),
11 | },
12 |
13 | module: {
14 | loaders: [
15 | {
16 | test: /\.tsx?$/,
17 | loaders: ['babel-loader', 'ts-loader']
18 | }
19 | ]
20 | },
21 | output: {
22 | filename: '[name].js',
23 | path: __dirname + "/static/",
24 | publicPath: "/static/",
25 | include: __dirname
26 | },
27 | plugins: [
28 | new webpack.HotModuleReplacementPlugin(),
29 | new webpack.NoErrorsPlugin(),
30 | new webpack.DefinePlugin({
31 | 'process.env.NODE_ENV': '"development"'
32 | })
33 | ],
34 | resolve: {
35 | extensions: ['', '.jsx', '.js', '.tsx', '.ts']
36 | }
37 | };
38 |
--------------------------------------------------------------------------------
/webpack/webpack.prod.js:
--------------------------------------------------------------------------------
1 | var webpack = require('webpack');
2 | var path = require("path");
3 |
4 | module.exports = {
5 | entry: ['babel-polyfill', './index.tsx'],
6 |
7 | module: {
8 | loaders: [
9 | {
10 | test: /\.tsx?$/,
11 | loader: 'babel-loader!ts-loader'
12 | }
13 | ]
14 | },
15 | output: {
16 | filename: 'index.js',
17 | path: "./static/"
18 | },
19 | resolve: {
20 | extensions: ['', '.jsx', '.js', '.tsx', '.ts']
21 | },
22 | plugins: [
23 | new webpack.DefinePlugin({
24 | 'process.env': {
25 | 'NODE_ENV': '"production"'
26 | }
27 | })
28 | ]
29 | };
30 |
--------------------------------------------------------------------------------