Giter VIP home page Giter VIP logo

typescript-react-starter's Introduction

This repo is now deprecated. In the time since it created TypeScript support is now a default feature of Create React App, Next.JS and Razzle.

This means you can get started with:

# Creates an app called my-app
npx create-react-app my-app --typescript

cd my-app

# Adds the type definitions
npm install --save typescript @types/node @types/react @types/react-dom @types/jest

echo "Good to go :tada:"

This repo offers some exmples on how to take that project into production and handle testing and state. However, you can also use the official documentation in the Create React App website for that.

If you'd like to know more about how to effectively do React with TypeScript, we recommend looking at the following:

Below is the original README for this sample.


TypeScript React Starter

This quick start guide will teach you how to wire up TypeScript with React. By the end, you'll have

  • a project with React and TypeScript
  • linting with TSLint
  • testing with Jest and Enzyme, and
  • state management with Redux

We'll use the create-react-app tool to quickly get set up.

We assume that you're already using Node.js with npm. You may also want to get a sense of the basics with React.

Install create-react-app

We're going to use the create-react-app because it sets some useful tools and canonical defaults for React projects. This is just a command-line utility to scaffold out new React projects.

npm install -g create-react-app

Create our new project

We'll create a new project called my-app:

create-react-app my-app --scripts-version=react-scripts-ts

react-scripts-ts is a set of adjustments to take the standard create-react-app project pipeline and bring TypeScript into the mix.

At this point, your project layout should look like the following:

my-app/
├─ .gitignore
├─ images.d.ts
├─ node_modules/
├─ public/
├─ src/
│  └─ ...
├─ package.json
├─ tsconfig.json
├─ tsconfig.prod.json
├─ tsconfig.test.json
└─ tslint.json

Of note:

  • tsconfig.json contains TypeScript-specific options for our project.
    • We also have a tsconfig.prod.json and a tsconfig.test.json in case we want to make any tweaks to our production builds, or our test builds.
  • tslint.json stores the settings that our linter, TSLint, will use.
  • package.json contains our dependencies, as well as some shortcuts for commands we'd like to run for testing, previewing, and deploying our app.
  • public contains static assets like the HTML page we're planning to deploy to, or images. You can delete any file in this folder apart from index.html.
  • src contains our TypeScript and CSS code. index.tsx is the entry-point for our file, and is mandatory.
  • images.d.ts will tell TypeScript that certain types of image files can be import-ed, which create-react-app supports.

Setting up source control

Our testing tool, Jest, expects some form of source control (such as Git or Mercurial) to be present. For it to run correctly, we'll need to initialize a git repository.

git init
git add .
git commit -m "Initial commit."

Note: if you've cloned this repository, you won't have to run the above at all.

Overriding defaults

The TSLint configuration that react-scripts-ts sets us up with is a bit overzealous. Let's fix that up.

 {
-  "extends": ["tslint:recommended", "tslint-react", "tslint-config-prettier"],
+  "extends": [],
+  "defaultSeverity": "warning",
   "linterOptions": {
     "exclude": [
       "config/**/*.js",
       "node_modules/**/*.ts"
     ]
   }
 }

Configuring TSLint is out of the scope of this starter, but you should feel free to experiment with something that works for you.

Running the project

Running the project is as simple as running

npm run start

This runs the start script specified in our package.json, and will spawn off a server which reloads the page as we save our files. Typically the server runs at http://localhost:3000, but should be automatically opened for you.

This tightens the iteration loop by allowing us to quickly preview changes.

Testing the project

Testing is also just a command away:

npm run test

This command runs Jest, an incredibly useful testing utility, against all files whose extensions end in .test.ts or .spec.ts. Like with the npm run start command, Jest will automatically run as soon as it detects changes. If you'd like, you can run npm run start and npm run test side by side so that you can preview changes and test them simultaneously.

Creating a production build

When running the project with npm run start, we didn't end up with an optimized build. Typically, we want the code we ship to users to be as fast and small as possible. Certain optimizations like minification can accomplish this, but often take more time. We call builds like this "production" builds (as opposed to development builds).

To run a production build, just run

npm run build

This will create an optimized JS and CSS build in ./build/static/js and ./build/static/css respectively.

You won't need to run a production build most of the time, but it is useful if you need to measure things like the final size of your app.

Creating a component

We're going to write a Hello component. The component will take the name of whoever we want to greet (which we'll call name), and optionally, the number of exclamation marks to trail with (enthusiasmLevel).

When we write something like <Hello name="Daniel" enthusiasmLevel={3} />, the component should render to something like <div>Hello Daniel!!!</div>. If enthusiasmLevel isn't specified, the component should default to showing one exclamation mark. If enthusiasmLevel is 0 or negative, it should throw an error.

We'll write a Hello.tsx:

// src/components/Hello.tsx

import * as React from 'react';

export interface Props {
  name: string;
  enthusiasmLevel?: number;
}

function Hello({ name, enthusiasmLevel = 1 }: Props) {
  if (enthusiasmLevel <= 0) {
    throw new Error('You could be a little more enthusiastic. :D');
  }

  return (
    <div className="hello">
      <div className="greeting">
        Hello {name + getExclamationMarks(enthusiasmLevel)}
      </div>
    </div>
  );
}

export default Hello;

// helpers

function getExclamationMarks(numChars: number) {
  return Array(numChars + 1).join('!');
}

Notice that we defined a type named Props that specifies the properties our component will take. name is a required string, and enthusiasmLevel is an optional number (which you can tell from the ? that we wrote out after its name).

We also wrote Hello as a stateless function component (an SFC). To be specific, Hello is a function that takes a Props object, and picks apart (or "destructures") all the properties that it will be passed. If enthusiasmLevel isn't given in our Props object, it will default to 1.

Writing functions is one of two primary ways React allows us to make components. If we wanted, we could have written it out as a class as follows:

class Hello extends React.Component<Props, object> {
  render() {
    const { name, enthusiasmLevel = 1 } = this.props;

    if (enthusiasmLevel <= 0) {
      throw new Error('You could be a little more enthusiastic. :D');
    }

    return (
      <div className="hello">
        <div className="greeting">
          Hello {name + getExclamationMarks(enthusiasmLevel)}
        </div>
      </div>
    );
  }
}

Classes are useful when our component instances have some state or need to handle lifecycle hooks. But we don't really need to think about state in this specific example - in fact, we specified it as object in React.Component<Props, object>, so writing an SFC makes more sense here, but it's important to know how to write a class component.

Notice that the class extends React.Component<Props, object>. The TypeScript-specific bit here are the type arguments we're passing to React.Component: Props and object. Here, Props is the type of our class's this.props, and object is the type of this.state. We'll return to component state in a bit.

Now that we've written our component, let's dive into index.tsx and replace our render of <App /> with a render of <Hello ... />.

First we'll import it at the top of the file:

import Hello from './components/Hello';

and then change up our render call:

ReactDOM.render(
  <Hello name="TypeScript" enthusiasmLevel={10} />,
  document.getElementById('root') as HTMLElement
);

Type assertions

One thing we'll point out in this section is the line document.getElementById('root') as HTMLElement. This syntax is called a type assertion, sometimes also called a cast. This is a useful way of telling TypeScript what the real type of an expression is when you know better than the type checker.

The reason we need to do so in this case is that getElementById's return type is HTMLElement | null. Put simply, getElementById returns null when it can't find an element with a given id. We're assuming that getElementById will actually succeed, so we need to convince TypeScript of that using the as syntax.

TypeScript also has a trailing "bang" syntax (!), which removes null and undefined from the prior expression. So we could have written document.getElementById('root')!, but in this case we wanted to be a bit more explicit.

Stateful components

We mentioned earlier that our component didn't need state. What if we wanted to be able to update our components based on user interaction over time? At that point, state becomes more important.

Deeply understanding best practices around component state in React are out of the scope of this starter, but let's quickly peek at a stateful version of our Hello component to see what adding state looks like. We're going to render two <button>s which update the number of exclamation marks that a Hello component displays.

To do that, we're going to

  1. Define a type for our state (i.e. this.state)
  2. Initialize this.state based on the props we're given in our constructor.
  3. Create two event handlers for our buttons (onIncrement and onDecrement).
// src/components/StatefulHello.tsx

import * as React from "react";

export interface Props {
  name: string;
  enthusiasmLevel?: number;
}

interface State {
  currentEnthusiasm: number;
}

class Hello extends React.Component<Props, State> {
  constructor(props: Props) {
    super(props);
    this.state = { currentEnthusiasm: props.enthusiasmLevel || 1 };
  }

  onIncrement = () => this.updateEnthusiasm(this.state.currentEnthusiasm + 1);
  onDecrement = () => this.updateEnthusiasm(this.state.currentEnthusiasm - 1);

  render() {
    const { name } = this.props;

    if (this.state.currentEnthusiasm <= 0) {
      throw new Error('You could be a little more enthusiastic. :D');
    }

    return (
      <div className="hello">
        <div className="greeting">
          Hello {name + getExclamationMarks(this.state.currentEnthusiasm)}
        </div>
        <button onClick={this.onDecrement}>-</button>
        <button onClick={this.onIncrement}>+</button>
      </div>
    );
  }

  updateEnthusiasm(currentEnthusiasm: number) {
    this.setState({ currentEnthusiasm });
  }
}

export default Hello;

function getExclamationMarks(numChars: number) {
  return Array(numChars + 1).join('!');
}

Notice:

  1. Much like with Props, we had to define a new type for our state: State.
  2. To update state in React, we use this.setState - we don't set it directly except in the constructor. setState only takes the properties we're interested in updating and our component will re-render as appropriate.
  3. We're using class property initializers with arrow functions (e.g. onIncrement = () => ...).
  • Declaring these as arrow functions avoids issues with orphaned uses of this.
  • Setting them as instance properties creates them only once - a common mistake is to initialize them in the render method which allocates closures one every call to render.

We won't use this stateful component any further in this starter. Stateful components are great for creating components that focus solely on presenting content (as opposed to handling core application state). In some contexts, it can be used for handling your entire application's state, with one central component passing down functions that can call setState appropriately; however, for much larger applications, a dedicated state manager might be preferable (as we'll discuss below).

Adding style 😎

Styling a component with our setup is easy. To style our Hello component, we can create a CSS file at src/components/Hello.css.

.hello {
  text-align: center;
  margin: 20px;
  font-size: 48px;
  font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
}

.hello button {
  margin-left: 25px;
  margin-right: 25px;
  font-size: 40px;
  min-width: 50px;
}

The tools that create-react-app uses (namely, Webpack and various loaders) allow us to just import the stylesheets we're interested in. When our build runs, any imported .css files will be concatenated into an output file. So in src/components/Hello.tsx, we'll add the following import.

import './Hello.css';

Writing tests with Jest

We had a certain set of assumptions about our Hello component. Let's reiterate what they were:

  • When we write something like <Hello name="Daniel" enthusiasmLevel={3} />, the component should render to something like <div>Hello Daniel!!!</div>.
  • If enthusiasmLevel isn't specified, the component should default to showing one exclamation mark.
  • If enthusiasmLevel is 0 or negative, it should throw an error.

We can use these requirements to write a few tests for our components.

But first, let's install Enzyme. Enzyme is a common tool in the React ecosystem that makes it easier to write tests for how components will behave. By default, our application includes a library called jsdom to allow us to simulate the DOM and test its runtime behavior without a browser. Enzyme is similar, but builds on jsdom and makes it easier to make certain queries about our components.

Let's install it as a development-time dependency.

npm install -D enzyme @types/enzyme enzyme-adapter-react-16 @types/enzyme-adapter-react-16 react-test-renderer

Notice we installed packages enzyme as well as @types/enzyme. The enzyme package refers to the package containing JavaScript code that actually gets run, while @types/enzyme is a package that contains declaration files (.d.ts files) so that TypeScript can understand how you can use Enzyme. You can learn more about @types packages here.

We also had to install enzyme-adapter-react-16 and react-test-renderer. This is something enzyme expects to be installed.

Before writing the first test, we have to configure Enzyme to use an adapter for React 16. We'll create a file called src/setupTests.ts that is automatically loaded when running tests:

import * as enzyme from 'enzyme';
import * as Adapter from 'enzyme-adapter-react-16';

enzyme.configure({ adapter: new Adapter() });

Now that we've got Enzyme set up, let's start writing our test! Let's create a file named src/components/Hello.test.tsx, adjacent to our Hello.tsx file from earlier.

// src/components/Hello.test.tsx

import * as React from 'react';
import * as enzyme from 'enzyme';
import Hello from './Hello';

it('renders the correct text when no enthusiasm level is given', () => {
  const hello = enzyme.shallow(<Hello name='Daniel' />);
  expect(hello.find(".greeting").text()).toEqual('Hello Daniel!')
});

it('renders the correct text with an explicit enthusiasm of 1', () => {
  const hello = enzyme.shallow(<Hello name='Daniel' enthusiasmLevel={1}/>);
  expect(hello.find(".greeting").text()).toEqual('Hello Daniel!')
});

it('renders the correct text with an explicit enthusiasm level of 5', () => {
  const hello = enzyme.shallow(<Hello name='Daniel' enthusiasmLevel={5} />);
  expect(hello.find(".greeting").text()).toEqual('Hello Daniel!!!!!');
});

it('throws when the enthusiasm level is 0', () => {
  expect(() => {
    enzyme.shallow(<Hello name='Daniel' enthusiasmLevel={0} />);
  }).toThrow();
});

it('throws when the enthusiasm level is negative', () => {
  expect(() => {
    enzyme.shallow(<Hello name='Daniel' enthusiasmLevel={-1} />);
  }).toThrow();
});

These tests are extremely basic, but you should be able to get the gist of things.

Adding state management

At this point, if all you're using React for is fetching data once and displaying it, you can consider yourself done. But if you're developing an app that's more interactive, then you may need to add state management.

State management in general

On its own, React is a useful library for creating composable views. However, React doesn't prescribe any specific way of synchronizing data throughout your application. As far as a React component is concerned, data flows down through its children through the props you specify on each element. Some of those props might be functions that update the state one way or another, but how that happens is an open question.

Because React on its own does not focus on application state management, the React community uses libraries like Redux and MobX.

Redux relies on synchronizing data through a centralized and immutable store of data, and updates to that data will trigger a re-render of our application. State is updated in an immutable fashion by sending explicit action messages which must be handled by functions called reducers. Because of the explicit nature, it is often easier to reason about how an action will affect the state of your program.

MobX relies on functional reactive patterns where state is wrapped through observables and passed through as props. Keeping state fully synchronized for any observers is done by simply marking state as observable. As a nice bonus, the library is already written in TypeScript.

There are various merits and tradeoffs to both. Generally Redux tends to see more widespread usage, so for the purposes of this tutorial, we'll focus on adding Redux; however, you should feel encouraged to explore both.

The following section may have a steep learning curve. We strongly suggest you familiarize yourself with Redux through its documentation.

Setting the stage for actions

It doesn't make sense to add Redux unless the state of our application changes. We need a source of actions that will trigger changes to take place. This can be a timer, or something in the UI like a button.

For our purposes, we're going to add two buttons to control the enthusiasm level for our Hello component.

Installing Redux

To add Redux, we'll first install redux and react-redux, as well as their types, as a dependency.

npm install -S redux react-redux @types/react-redux

In this case we didn't need to install @types/redux because Redux already comes with its own definition files (.d.ts files).

Defining our app's state

We need to define the shape of the state which Redux will store. For this, we can create a file called src/types/index.tsx which will contain definitions for types that we might use throughout the program.

// src/types/index.tsx

export interface StoreState {
    languageName: string;
    enthusiasmLevel: number;
}

Our intention is that languageName will be the programming language this app was written in (i.e. TypeScript or JavaScript) and enthusiasmLevel will vary. When we write our first container, we'll understand why we intentionally made our state slightly different from our props.

Adding actions

Let's start off by creating a set of message types that our app can respond to in src/constants/index.tsx.

// src/constants/index.tsx

export const INCREMENT_ENTHUSIASM = 'INCREMENT_ENTHUSIASM';
export type INCREMENT_ENTHUSIASM = typeof INCREMENT_ENTHUSIASM;


export const DECREMENT_ENTHUSIASM = 'DECREMENT_ENTHUSIASM';
export type DECREMENT_ENTHUSIASM = typeof DECREMENT_ENTHUSIASM;

This const/type pattern allows us to use TypeScript's string literal types in an easily accessible and refactorable way.

Next, we'll create a set of actions and functions that can create these actions in src/actions/index.tsx.

import * as constants from '../constants';

export interface IncrementEnthusiasm {
    type: constants.INCREMENT_ENTHUSIASM;
}

export interface DecrementEnthusiasm {
    type: constants.DECREMENT_ENTHUSIASM;
}

export type EnthusiasmAction = IncrementEnthusiasm | DecrementEnthusiasm;

export function incrementEnthusiasm(): IncrementEnthusiasm {
    return {
        type: constants.INCREMENT_ENTHUSIASM
    }
}

export function decrementEnthusiasm(): DecrementEnthusiasm {
    return {
        type: constants.DECREMENT_ENTHUSIASM
    }
}

We've created two types that describe what increment actions and decrement actions should look like. We also created a type (EnthusiasmAction) to describe cases where an action could be an increment or a decrement. Finally, we made two functions that actually manufacture the actions which we can use instead of writing out bulky object literals.

There's clearly boilerplate here, so you should feel free to look into libraries like redux-actions once you've got the hang of things.

Adding a reducer

We're ready to write our first reducer! Reducers are just functions that generate changes by creating modified copies of our application's state, but that have no side effects. In other words, they're what we call pure functions.

Our reducer will go under src/reducers/index.tsx. Its function will be to ensure that increments raise the enthusiasm level by 1, and that decrements reduce the enthusiasm level by 1, but that the level never falls below 1.

// src/reducers/index.tsx

import { EnthusiasmAction } from '../actions';
import { StoreState } from '../types/index';
import { INCREMENT_ENTHUSIASM, DECREMENT_ENTHUSIASM } from '../constants/index';

export function enthusiasm(state: StoreState, action: EnthusiasmAction): StoreState {
  switch (action.type) {
    case INCREMENT_ENTHUSIASM:
      return { ...state, enthusiasmLevel: state.enthusiasmLevel + 1 };
    case DECREMENT_ENTHUSIASM:
      return { ...state, enthusiasmLevel: Math.max(1, state.enthusiasmLevel - 1) };
  }
  return state;
}

Notice that we're using the object spread (...state) which allows us to create a shallow copy of our state, while replacing the enthusiasmLevel. It's important that the enthusiasmLevel property come last, since otherwise it would be overridden by the property in our old state.

You may want to write a few tests for your reducer. Since reducers are pure functions, they can be passed arbitrary data. For every input, reducers can be tested by checking their newly produced state. Consider looking into Jest's toEqual method to accomplish this.

Making a container

When writing with Redux, we will often write components as well as containers. Components are often data-agnostic, and work mostly at a presentational level. Containers typically wrap components and feed them any data that is necessary to display and modify state. You can read more about this concept on Dan Abramov's article Presentational and Container Components.

First let's update src/components/Hello.tsx so that it can modify state. We'll add two optional callback properties to Props named onIncrement and onDecrement:

export interface Props {
  name: string;
  enthusiasmLevel?: number;
  onIncrement?: () => void;
  onDecrement?: () => void;
}

Then we'll bind those callbacks to two new buttons that we'll add into our component.

function Hello({ name, enthusiasmLevel = 1, onIncrement, onDecrement }: Props) {
  if (enthusiasmLevel <= 0) {
    throw new Error('You could be a little more enthusiastic. :D');
  }

  return (
    <div className="hello">
      <div className="greeting">
        Hello {name + getExclamationMarks(enthusiasmLevel)}
      </div>
      <div>
        <button onClick={onDecrement}>-</button>
        <button onClick={onIncrement}>+</button>
      </div>
    </div>
  );
}

In general, it'd be a good idea to write a few tests for onIncrement and onDecrement being triggered when their respective buttons are clicked. Give it a shot to get the hang of writing tests for your components.

Now that our component is updated, we're ready to wrap it into a container. Let's create a file named src/containers/Hello.tsx and start off with the following imports.

import Hello from '../components/Hello';
import * as actions from '../actions/';
import { StoreState } from '../types/index';
import { connect, Dispatch } from 'react-redux';

The real two key pieces here are the original Hello component as well as the connect function from react-redux. connect will be able to actually take our original Hello component and turn it into a container using two functions:

  • mapStateToProps which massages the data from the current store to part of the shape that our component needs.
  • mapDispatchToProps which creates callback props to pump actions to our store using a given dispatch function.

If we recall, our application state consists of two properties: languageName and enthusiasmLevel. Our Hello component, on the other hand, expected a name and an enthusiasmLevel. mapStateToProps will get the relevant data from the store, and adjust it if necessary, for our component's props. Let's go ahead and write that.

export function mapStateToProps({ enthusiasmLevel, languageName }: StoreState) {
  return {
    enthusiasmLevel,
    name: languageName,
  }
}

Note that mapStateToProps only creates 2 out of 4 of the properties a Hello component expects. Namely, we still want to pass in the onIncrement and onDecrement callbacks. mapDispatchToProps is a function that takes a dispatcher function. This dispatcher function can pass actions into our store to make updates, so we can create a pair of callbacks that will call the dispatcher as necessary.

export function mapDispatchToProps(dispatch: Dispatch<actions.EnthusiasmAction>) {
  return {
    onIncrement: () => dispatch(actions.incrementEnthusiasm()),
    onDecrement: () => dispatch(actions.decrementEnthusiasm()),
  }
}

Finally, we're ready to call connect. connect will first take mapStateToProps and mapDispatchToProps, and then return another function that we can use to wrap our component. Our resulting container is defined with the following line of code:

export default connect(mapStateToProps, mapDispatchToProps)(Hello);

When we're finished, our file should look like this:

// src/containers/Hello.tsx

import Hello from '../components/Hello';
import * as actions from '../actions/';
import { StoreState } from '../types/index';
import { connect, Dispatch } from 'react-redux';

export function mapStateToProps({ enthusiasmLevel, languageName }: StoreState) {
  return {
    enthusiasmLevel,
    name: languageName,
  }
}

export function mapDispatchToProps(dispatch: Dispatch<actions.EnthusiasmAction>) {
  return {
    onIncrement: () => dispatch(actions.incrementEnthusiasm()),
    onDecrement: () => dispatch(actions.decrementEnthusiasm()),
  }
}

export default connect(mapStateToProps, mapDispatchToProps)(Hello);

Creating a store

Let's go back to src/index.tsx. To put this all together, we need to create a store with an initial state, and set it up with all of our reducers.

import { createStore } from 'redux';
import { enthusiasm } from './reducers/index';
import { StoreState } from './types/index';

const store = createStore<StoreState>(enthusiasm, {
  enthusiasmLevel: 1,
  languageName: 'TypeScript',
});

store is, as you might've guessed, our central store for our application's global state.

Next, we're going to swap our use of ./src/components/Hello with ./src/containers/Hello and use react-redux's Provider to wire up our props with our container. We'll import each:

import Hello from './containers/Hello';
import { Provider } from 'react-redux';

and pass our store through to the Provider's attributes:

ReactDOM.render(
  <Provider store={store}>
    <Hello />
  </Provider>,
  document.getElementById('root') as HTMLElement
);

Notice that Hello no longer needs props, since we used our connect function to adapt our application's state for our wrapped Hello component's props.

Ejecting

If at any point, you feel like there are certain customizations that the create-react-app setup has made difficult, you can always opt-out and get the various configuration options you need. For example, if you'd like to add a Webpack plugin, it might be necessary to take advantage of the "eject" functionality that create-react-app provides.

Simply run

npm run eject

and you should be good to go!

As a heads up, you may want to commit all your work before running an eject. You cannot undo an eject command, so opting out is permanent unless you can recover from a commit prior to running an eject.

Next steps

create-react-app comes with a lot of great stuff. Much of it is documented in the default README.md that was generated for our project, so give that a quick read.

If you still want to learn more about Redux, you can check out the official website for documentation. The same goes for MobX.

If you want to eject at some point, you may need to know a little bit more about Webpack. You can check out our React & Webpack walkthrough here.

At some point you might need routing. There are several solutions, but react-router is probably the most popular for Redux projects, and is often used in conjunction with react-router-redux.

typescript-react-starter's People

Contributors

aarongreenlee avatar catchin avatar danielrosenwasser avatar dmitriz avatar kachick avatar lazarljubenovic avatar mattywong avatar microsoftopensource avatar msftgits avatar phaedryx avatar renatoselenica avatar sandersn avatar scottsauber avatar svenheden avatar tugberkugurlu 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

typescript-react-starter's Issues

Hot reload doesn't work

Hot reload works properly with just create-react-app but doesn't work with react-scripts-ts.

I have included following in index.tsx

if ((module as any).hot) {
  (module as any).hot.accept('./App', () => {
    const NextApp = require('./App').default;
    ReactDOM.render(<NextApp />, document.getElementById('root'));
  });
}

Since I am using create-react-app that uses webpack-2, I have tried following also:

if ((module as any).hot) {
  (module as any).hot.accept('./App', () => {
    ReactDOM.render(<App />, document.getElementById('root'));
  });
}

But still it doesn't work. CSS hot reload works btw. I also converted my App component to pure function instead of class but to no avail.

Following are the versions:
create-react-app - 1.3.3
react-scripts-ts - 2.4.0

Please help!

please allow js/jsx components

Hi
I'm developing my project in typescript with this starter but I'd like to have a few components to be written in js/jsx. Currently it does not work, I receive strange error like this:

InvalidCharacterError: Failed to execute 'createElement' on 'Document': The tag name provided ('/static/media/Alma.60238e91.jsx') is not a valid name.

Creating Tests for Button Click

The documentation says:

In general, it'd be a good idea to write a few tests for onIncrement and onDecrement being triggered when their respective buttons are clicked. Give it a shot to get the hang of writing tests for your components.

It would be great if someone could provide the code to how to test for button clicks, I'm a n00b at this framework (And nodejs as a whole) so i'd love to see how the tests for button clicks are made?

Fails with newer versions of packages

Failed to compile.

Error in ./src/index.tsx
(19,5): error TS2322: Type '{}' is not assignable to type 'IntrinsicAttributes & IntrinsicClassAttributes<Component<Props, ComponentState>> & Readonly<{ chi...'.
  Type '{}' is not assignable to type 'Readonly<Props>'.
    Property 'name' is missing in type '{}'.

It looks like it wants the name to be supplied even tho it comes from the container, I'm not sure if it's a bug in newer types versions or it's a new requirements how do you deal with it?

Thanks

import fails with 'no default export'

This import works fine under babel:

import React from "react";

But under TypeScript it complains of:
(1,8): error TS1192: Module '"/Volumes/repos/tc-web-ts/node_modules/@types/react/index"' has no default export.

Enzyme problem. Has no exported member 'AllHTMLAttributes'

I cloned the respository.
npm i
npm run start.

Failed to compile.

Error in C:\projects\work\TypeScript-React-Starter\node_modules@types\enzyme\index.d.ts
(13,35): error TS2305: Module '"C:/projects/work/TypeScript-React-Starter/node_modules/@types/react/index"' has no exported member 'AllHTMLAttributes'.

I am running windows 10. npm 5.3, node v6.9.5.

Code Splitting using dynamic imports fails for tests

Hi team,

I've been running through setting up a new create-react-app project with typescript, and have gotten to code splitting using the dynamic import syntax. This works great when I run up the project with npm start.

However, when I run npm test, it fails with an "Unexpected token" error pointing to the dynamic import keyword. This seems to indicate to me that when the code is being run for the tests, the import is not being converted into a node-friendly require.

My node version: v8.5.0
Typescript version: 2.4.2 (this is currently pinned to ~2.4.0 by react-scripts-ts)

This starter already has tsconfig.test.json with the module to "commonjs" (which I believe should cause the import to be converted).

This issue seems to indicate that a bug existed that caused it to not be converted correctly in all cases. However I have not been able to get it working at all. Additionally, after seeing this bug, I tried a local hack to use typescript 2.5.2 to see if that helped, but no joy.

Is this a bug somewhere in the toolchain, or is there something obvious that I'm missing? :)

Hello.tsx when hello is a class, it breaks....

This is a great starting tutorial, and got me up to speed quickly for converting react to typescript.
If I follow exactly. It works. However, I wanted to use this as a base to learn from , and am running into issues if I am using a component that is a class instead of a straight functional component.

`
class Hello extends React.Component<Props, object> {
render() {
const { name, enthusiasmLevel = 1 } = this.props;

if (enthusiasmLevel <= 0) {
  throw new Error('You could be a little more enthusiastic. :D');
}

return (
  <div className="hello">
    <div className="greeting">
      Hello {name + getExclamationMarks(enthusiasmLevel)}
    </div>
  </div>
);

}
}

`

is the example for writing this out as a class.

If I modify it slightly , and modify the interface for the props my code looks like this.

`import * as React from 'react';
import './Hello.css';

export interface Props {
name: string;
enthusiasmLevel?: number;
onIncrement?: () => void;
onDecrement?: () => void;
}

class Hello extends React.Component<Props, object> {
render() {
const { name, enthusiasmLevel = 1 } = this.props;

if (enthusiasmLevel <= 0) {
  throw new Error('You could be a little more enthusiastic. :D');
}

return (
  <div className="hello">
    <div className="greeting">
      Hello {name + getExclamationMarks(enthusiasmLevel)}
    </div>
    <div>
    <button onClick={this.props.onDecrement}>-</button>
    <button onClick={this.props.onIncrement}>+</button>
  </div>
  </div>
);

}
}

export default Hello;

function getExclamationMarks(numChars: number) {
return Array(numChars + 1).join('!');
}`

However this blows up my container. I get a failed to compile error:
/src/containers/Hello.tsx (20,61): error TS2345: Argument of type 'typeof Hello' is not assignable to parameter of type 'Component<{ enthusiasmLevel: number; name: string; } & { onIncrement: () => IncrementEnthusiasm; .. .'. Type 'typeof Hello' is not assignable to type 'StatelessComponent<{ enthusiasmLevel: number; na me: string; } & { onIncrement: () => IncrementEnt...'. Type 'typeof Hello' provides no match for the signature '(props: { enthusiasmLevel: number; n ame: string; } & { onIncrement: () => IncrementEnthusiasm; onDecrement: () => DecrementEnthusiasm ; } & { children?: ReactNode; }, context?: any): ReactElement<any>'.

What am I doing wrong with using a class instead of functional component.

Broken link in README

At the bottom there is

If you want to eject at some point, you may need to know a little bit more about Webpack. You can check out our [React & Webpack walkthrough here](./React & Webpack.md).

As there isn't a document for React + Webpack, perhaps it's worth linking to the create-react-app one?

import static json files

The webpack setup in stock create-react-app supports this:

import customers from ‘./customers.json’

This is a very handy thing and I have come to rely upon it.

How to work with SASS?

Hi, can i use SCSS with this starter? Or i need manually create webpack config and setup tasks for this?
Thanks.

VSCode tasks.json

Firstly awesome work with this! Really helps reduce that initial setup time.

I just had a thought, could you include in this project or perhaps recommend a VSCode tasks.json file for matching compile problems when using this project?

That would make things even even faster for people using this as they are likely going to be using VSCode anyways.

error TS2604: JSX element type 'Provider' does not have any construct or call signatures.

I followed every step stated in the tutorial for setting up typescript with react and i get the error "error TS2604: JSX element type 'Provider' does not have any construct or call signatures." when i introduce the provider element into ReactDom as instructed in the book. I literally had to copy and paste each section of the tutorial to my code to make sure i wasn't making any mistakes. can someone please help me out?

Thanks

background: url(); not working

Hey everyone,

I don't know if this is expected or if I am doing something wrong.
I have a component Hero.tsx with import './Hero.css'; in it
and in my Hero.css I have:

.hero{
    background-image: url('../images/hero-background.jpg');
    min-width: 100vw;
    height:500px;
}

I now get the following error

Failed to compile
./src/components/Hero.css
Module not found: Can't resolve '../images/hero-background.jpg' in '/Users/kevin.peters/test/my-app/src/components'
This error occurred during the build time and cannot be dismissed.

My folder structure is like this:

src 
| components
| | Header.tsx
| | Header.css
| images
| | hero-background.jpg
| App.tsx
| ...

Am I just screwing up the path? I put the file in my components folder and used url(hero-background.jpg) with quotes, without quotes, with and without ./ but it always gives me the same Type of error.

I'm getting errors with Redux example

I'm trying to define constants like on the following example:

image

my code:
image

And I'm trying to define the actions, however I'm getting the following error:

image

I'm just following the example on README, any help will be appreciated.
Best Regards.

Cannot read property 'getStart' of undefined

My app works perfectly with no warnings or errors in dev mode (yarn start). But I am getting an error when I attempt a build (yarn build):

df2:client dford$ yarn build
yarn build v0.23.2
$ react-scripts-ts build 
Creating an optimized production build...
ts-loader: Using [email protected] and /Volumes/repos/tc-web/client/tsconfig.json
Warning: Cannot read property 'getStart' of undefined
Failed to compile.

The string getStart appears no where in my code.

with tslint.json configuration:

{
  "extends": [
    "tslint-react"
  ],
  "rules": {
    "jsx-no-lambda": false
  }
}

Production build failing: Unexpected token: operator (>)

My app works perfectly in dev mode (yarn start). But when I go to build it (yarn build) I get an error:

df2:client dford$ yarn build
yarn build v0.23.2
$ react-scripts-ts build 
Creating an optimized production build...
ts-loader: Using [email protected] and /Volumes/repos/tc-web/client/tsconfig.json
Failed to compile.

static/js/main.5896ebe9.js from UglifyJs
SyntaxError: Unexpected token: operator (>) [./~/tslint-loader!./src/Testimonials.tsx:11,14]

It seems as though tslint is rejecting arrow functions?

I posted an issue to tslint and they responded with this:

TSLint 4.0.2 is a very old version and is not designed to work with TS 2.3 (it's six months older). Please upgrade TSLint.

JSX element type 'App' is not a constructor

Following the readme tutorial, after changing the original render function to render the new 'Hello' component, the error is

(7,3): error TS2605: JSX element type 'App' is not a constructor function for JSX elements.
Types of property 'render' are incompatible.
Type '() => void | Element | Component<any, ComponentState>' is not assignable to type '() => Element | null'.
Type 'void | Element | Component<any, ComponentState>' is not assignable to type 'Element | null'.
Type 'void' is not assignable to type 'Element | null'.

The code is

class App extends React.Component<{}, null> {
    render() {
        return ReactDOM.render(
            <Hello name="TypeScript" enthusiasmLevel={10} />,
            document.getElementById('root') as HTMLElement
        );
    }
}

Visual Studio Code 1.12.1
TypeScript React 2.3.2
npm 3.10.10

windows typescript-react-starter got issue

Hi Team,

Trying to install npm react-scripts-ts not working in Windows7 - 64-bit Process.

find my node , npm versions in below for reference.

C:\Users\125\NodeJS\reactjs>npm --version
5.3.0

C:\Users\125\NodeJS\reactjs>node --version
v6.11.1

C:\Users\125\NodeJS\reactjs>npm install -g create-react-app
C:\Users\125\AppData\Roaming\npm\create-react-app -> C:\Users\125\AppD
ata\Roaming\npm\node_modules\create-react-app\index.js

C:\Users\125\NodeJS\reactjs>create-react-app my-app --scripts-version=react
-scripts-ts
Creating a new React app in C:\Users\125\NodeJS\reactjs\my-app.

Installing packages. This might take a couple of minutes.
Installing react, react-dom, and react-scripts-ts...

npm ERR! path C:\Users\125\NodeJS\reactjs\my-app\node_modules\fsevents\node
_modules\tar-pack\node_modules
npm ERR! code EPERM
npm ERR! errno -4048
npm ERR! syscall scandir
npm ERR! Error: EPERM: operation not permitted, scandir 'C:\Users\125\NodeJ
S\reactjs\my-app\node_modules\fsevents\node_modules\tar-pack\node_modules'
npm ERR! at Error (native)
npm ERR! { Error: EPERM: operation not permitted, scandir 'C:\Users\125\No
deJS\reactjs\my-app\node_modules\fsevents\node_modules\tar-pack\node_modules'
npm ERR! at Error (native)
npm ERR! stack: 'Error: EPERM: operation not permitted, scandir 'C:\Users\5
0030059\NodeJS\reactjs\my-app\node_modules\fsevents\node_modules\tar-pack
\node_modules'\n at Error (native)',
npm ERR! errno: -4048,
npm ERR! code: 'EPERM',
npm ERR! syscall: 'scandir',
npm ERR! path: 'C:\Users\125\NodeJS\reactjs\my-app\node_modules\fs
events\node_modules\tar-pack\node_modules' }
npm ERR!
npm ERR! Please try running this command again as root/Administrator.

npm ERR! A complete log of this run can be found in:
npm ERR! C:\Users\125\AppData\Roaming\npm-cache_logs\2017-07-27T13_56_
32_175Z-debug.log

Aborting installation.
npm install --save --save-exact --loglevel error react react-dom react-scripts
-ts has failed.

Deleting generated file... node_modules
Deleting generated file... package.json
Deleting my-app / from C:\Users\125\NodeJS\reactjs
Done.

C:\Users\125\NodeJS\reactjs>

import images

This works with stock create-react-app:

import logo from "./ss-logo-transparent.png";

Errors prevent app from running at all

A key feature of TypeScript is that it still emits output, even when there are type errors. This allows code to still be run even in the presence of type errors. However, if I add let str: string = 1; to src/index.tsx in a brand new app, I only see the "Failed to compile" message in my browser.

Is there anyway I can get around this behavior? I'm perfectly content to only see the compilation errors in my console.

Unable to do initial `yarn` after cloning the repo down.

I've tried this several times to make sure it wasn't an off occurrence. When trying to install the dependencies, the runner exits and fails.

error

[1/4] 🔍  Resolving packages...
[2/4] 🚚  Fetching packages...
[3/4] 🔗  Linking dependencies...
[4/4] 📃  Building fresh packages...
[1/1] ⢀ fsevents: node-pre-gyp
[-/1] ⢀ waiting...
[-/1] ⢀ waiting...
[-/1] ⢀ waiting...
warning Error running install script for optional dependency: "/Users/maxorelus/Sites/cr-ui/node_modules/fsevents: Command failed.\nExit code: 1\nCommand: sh\nArguments: -c node-pre-gyp install --fallback-to-build\nDirectory: /Users/maxorelus/Sites/cr-ui/node_modules/fsevents\nOutput:\nnode-pre-gyp info it worked if it ends with ok\nnode-pre-gyp info using [email protected]\nnode-pre-gyp info using [email protected] | darwin | x64\nnode-pre-gyp info check checked for \"/Users/maxorelus/Sites/cr-ui/node_modules/fsevents/lib/binding/Release/node-v51-darwin-x64/fse.node\" (not found)\nnode-pre-gyp http GET https://fsevents-binaries.s3-us-west-2.amazonaws.com/v1.0.14/fse-v1.0.14-node-v51-darwin-x64.tar.gz\nnode-pre-gyp http 404 https://fsevents-binaries.s3-us-west-2.amazonaws.com/v1.0.14/fse-v1.0.14-node-v51-darwin-x64.tar.gz\nnode-pre-gyp ERR! Tried to download: https://fsevents-binaries.s3-us-west-2.amazonaws.com/v1.0.14/fse-v1.0.14-node-v51-darwin-x64.tar.gz \nnode-pre-gyp ERR! Pre-built binaries not found for [email protected] and [email protected] (node-v51 ABI) (falling back to source compile with node-gyp) \nnode-pre-gyp http Pre-built binary not available for your system, looked for https://fsevents-binaries.s3-us-west-2.amazonaws.com/v1.0.14/fse-v1.0.14-node-v51-darwin-x64.tar.gz \nnode-pre-gyp ERR! build error \nnode-pre-gyp ERR! stack Error: Failed to execute 'node-gyp clean' (Error: spawn node-gyp ENOENT)\nnode-pre-gyp ERR! stack     at ChildProcess.<anonymous> (/Users/maxorelus/Sites/cr-ui/node_modules/fsevents/node_modules/node-pre-gyp/lib/util/compile.js:77:29)\nnode-pre-gyp ERR! stack     at emitOne (events.js:96:13)\nnode-pre-gyp ERR! stack     at ChildProcess.emit (events.js:191:7)\nnode-pre-gyp ERR! stack     at Process.ChildProcess._handle.onexit (internal/child_process.js:213:12)\nnode-pre-gyp ERR! stack     at onErrorNT (internal/child_process.js:367:16)\nnode-pre-gyp ERR! stack     at _combinedTickCallback (internal/process/next_tick.js:80:11)\nnode-pre-gyp ERR! stack     at process._tickCallback (internal/process/next_tick.js:104:9)\nnode-pre-gyp ERR! System Darwin 16.6.0\nnode-pre-gyp ERR! command \"/usr/local/Cellar/node/7.10.0/bin/node\" \"/Users/maxorelus/Sites/cr-ui/node_modules/fsevents/node_modules/.bin/node-pre-gyp\" \"install\" \"--fallback-to-build\"\nnode-pre-gyp success Saved lockfile.
✨  Done in 12.70s.

System Specification

  • npm v4.6.1
  • Node v7.10.0
  • OSX Sierra

Support pwa?

In facebook offical create-react-app, it supports pwa by SWPrecacheWebpackPlugin.
pwa pull request
This feature is useless and progressive, will TypeScript-React-Starter add this feature?

Readme is confusing

I'm confused. Is this repo the result of using create-react-app with the react-scripts-ts script? Or should you use CRA and the react-script-ts script on top of this repo? Please advise.

Invalid @types/react version (5.0.14 should be 15.0.14)

This line should probably be 15 instead of 5

    "@types/react": "5.0.14",

https://github.com/Microsoft/TypeScript-React-Starter/blob/master/package.json#L13

That is causing this error on npm i

npm ERR! notarget No compatible version found: @types/[email protected]
npm ERR! notarget Valid install targets:
npm ERR! notarget 0.14.14-alpha, 0.14.15-alpha, 0.14.20-alpha, 0.14.21-alpha, 0.14.22-alpha, 0.14.23-alpha, 0.14.24-alpha, 0.14.25-alpha, 0.14.26-alpha, 0.14.27, 0.14.28, 0.14.29, 0.14.30, 0.14.31, 0.14.32, 0.14.33, 0.14.34, 0.14.35, 0.14.36, 0.14.37, 0.14.38,
0.14.39, 0.14.40, 0.14.41, 0.14.42, 0.14.43, 0.14.44, 0.14.45, 0.14.46, 0.14.47, 0.14.48, 0.14.49, 0.14.50, 0.14.51, 0.14.52, 0.14.53, 0.14.54, 0.14.55, 0.14.56, 0.14.57, 0.0.0, 15.0.0, 15.0.1, 15.0.2, 15.0.3, 15.0.4, 15.0.5, 15.0.6, 15.0.7, 15.0.8, 15.0.9, 15.
0.10, 15.0.11, 15.0.12, 15.0.13, 15.0.14, 15.0.15, 15.0.16, 15.0.17, 15.0.18, 15.0.19, 15.0.20, 15.0.21, 15.0.22, 15.0.23, 15.0.24

JSX element type 'App' is not a constructor function for JSX elements. Types of property 'setState' are incompatible.

I get this compile error during npm start:

./src/index.tsx
(16,5): error TS2605: JSX element type 'App' is not a constructor function for JSX elements.
  Types of property 'setState' are incompatible.
    Type '{ <K extends never>(f: (prevState: null, props: {}) => Pick<null, K>, callback?: (() => any) | un...' is not assignable to type '{ <K extends never>(f: (prevState: {}, props: any) => Pick<{}, K>, callback?: (() => any) | undef...'.
      Types of parameters 'f' and 'f' are incompatible.
        Type '(prevState: {}, props: any) => Pick<{}, any>' is not assignable to type '(prevState: null, props: {}) => Pick<null, any>'.
          Types of parameters 'prevState' and 'prevState' are incompatible.
            Type 'null' is not assignable to type '{}'.

My code:

class App extends React.Component<{}, null> {
  render() {
    return (
      <div className="App">
        ...
      </div>
    );
  }
}

ReactDOM.render(
  <Provider store={store}>
    <App />
  </Provider>,
  document.getElementById('root') as HTMLElement
);

I am using:
node v6.11.0
npm v5.1.0
typescript v2.4.1
react v15.6.1
redux v3.7.1
react-redux v5.0.5
react-scripts-ts v2.3.2

Install fails on incorrect typings version for React

The dependency version for @types/react is listed as 5.0.14 in package.json, which causes an error during the install because it's not a valid target. The current version is 15.0.24, unless you meant to lock it to a prior release (15.0.14?).

Updating input values in Composed components

Hi,
I created a simple test with a TestFormManager which contains a TestForm child component with an input.
I simply want to change the input value so the state in TestFormManager is updated.
The problem is that I can't change the value in the input at all. Even when debugging the handler (setPersonState) is raised and receives the key pressed in the Input, the value is not propagated to the child. So the initial state "Test" is always displayed and can't change it.
This test runs fine in react without typescript

TestFormManager:

import * as React from 'react';
import TestForm from './TestForm';

interface Person {    
  name: string;
}

export interface FormManagerProps {}

export interface FormManagerState {
  person : Person;
}
class AccountManager extends React.PureComponent < FormManagerProps, FormManagerState > {
  public state : FormManagerState;
  constructor() {
    super();
    this.state = {
      person: {        
        name: 'Test',
      }
    };
    this.setPersonState = this.setPersonState.bind(this);    
  }
  setPersonState(event: React.FormEvent<HTMLInputElement>) {    
    var field = event.currentTarget.name;
    var value = event.currentTarget.value;
    var currentState = this.state.person;
    currentState[field] = value;
    return this.setState({person: currentState});
  }

  render() {
    return (<TestForm person={this.state.person} onChange={this.setPersonState}/>);
  }
}

export default AccountManager;

And the TestForm

import * as React from 'react';

interface Person {    
  name: string;
}

export interface TestFormProps {
  person: Person;
  onChange: (event: React.FormEvent<HTMLInputElement>) => void;  
}

class TestForm extends React.Component < TestFormProps, {} > {  
  render() {    
    return (
      <div className="container">
        <form>
          <h1>Person Details:</h1>
          <input type="text" name={this.props.person.name} className="form-control" placeholder="Set the name"
            ref={this.props.person.name} value={this.props.person.name} onChange={e => this.props.onChange(e)}/>                 
          <br/>
          <input type="submit" value="save" className="btn btn-default" />
        </form>
      </div>
    );
  }
}

export default TestForm;

Property 'name' is missing

After completing all the steps of the tutorial having an error at index.tsx: 19

Property 'name' is missing in type 'IntrinsicAttributes & IntrinsicClassAttributes<Component<Props, ComponentState>> & Readonly<{ chi...'. my-app (tsconfig project)

Setting the name property fixes the issue and the sample works as expected:
<Hello name="something" />

(33,5): error TS2687: All declarations of 'value' must have identical modifiers.

Error comes from /node_modules/typescript/lib/lib.es2015.iterable.d.ts
Throws right after create-react-app my-app --scripts-version=react-scripts-ts is done with no warnings or errors, when executing yarn start. I am on a mac with OSX Yosemite 10.10.5 using create-react-app version 1.4.1, tsc version 2.3.2 and yarn version 1.1.0.

Why all tsx files ?

When the TypeScript file does not contain any JSX, why did you guys use .TSX instead of .TS ?

I know it does not really matter, but using .TSX signifies there is JSX inside.

Probably should keep .TS for plain TypeScript and .TSX when there is some JSX. Just my two cents for consistency.

run npm install -S redux react-redux @types/react-redux

run npm start
npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! **@0.1.0 start: react-scripts-ts start
npm ERR! Exit status 1
npm ERR!
npm ERR! Failed at the **@0.1.0 start script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.

Cannot debug the code

Hi, first I'd like to thank you for sharing step-by-step instructions how to easily create react+typescript project!

Anyway, I'm struggling how can I debug this project? I tried to create launch config for vscode (chrome debug extension is installed and working on other pure js projects) but with no success (breakpoint is not hit):

{
	"version": "0.2.0",
	"configurations": [{
		"name": "Chrome",
		"type": "chrome",
		"request": "launch",
		"url": "http://localhost:3000",
		"webRoot": "${workspaceRoot}/src",
		"userDataDir": "${workspaceRoot}/.vscode/chrome",
		"sourceMapPathOverrides": {
			"webpack:///src/*": "${webRoot}/*"
		}
	}]
}

Then I tried to debug it directly in chrome. If I get it right I should see the original source codes under "webpack://" node but unfortunately it's not there:

image

Is there any way how to make this project (or generally projects created this way) debug friendly?

table specific attributes

If I change the Hello.tsx content as follows,

  <table align="center"><tr><td>

    <div className="hello">
      <div className="greeting">
        Hello {name + getExclamationMarks(enthusiasmLevel)}
      </div>
      <div>
        <button onClick={onDecrement}>-</button>
        <button onClick={onIncrement}>+</button>
      </div>
    </div>

  </td></tr></table>

I get the following error:

Failed to compile.

Error in ./src/components/Hello.tsx
(17,10): error TS2339: Property 'align' does not exist on type 'HTMLProps'.
I noticed the same behaviour with latest TypeScript 2.3.2 on a different project as well.

Install create-react-app failed

Steps:

  1. npm install -g create-react-app
  2. create-react-app my-app --scripts-version=react-scripts-ts
  3. cd my-app
  4. npm start
    As a result don't complie with error:
    Module not found: Can't resolve 'react_start_kit\my-app\src\index.tsx' in 'D:_work!react_start_kit\my-app'

Error error TS6059: File '.../typescript-react-starter//src/App.test.tsx' is not under 'rootDir' '.../typescript-react-starter/src/src'. 'rootDir' is expected to contain all source files.

Hello,

I've tried to follow the steps in the readme, but I'm getting this strange error. I've followed the following steps:

1 - npm install -g create-react-app
2 - create-react-app typescript-react-starter --scripts-version=react-scripts-ts
3 - I have a structure similar to the one shown in the Readme, except for the yarn.lock and tsconfig.test.json files which I've got on my folder.
4 - After checking the folder structure, I've tried to fire up project by running npm start. However, the index page quickly flashes and then I got the following error, both in the browser and in vscode terminal:

error TS6059: File '/home/otmar/learning/typescript-react-starter/src/App.test.tsx' is not under 'rootDir' '/home/otmar/learning/typescript-react-starter/src/src'. 'rootDir' is expected to contain all source files.

Am I missing anything ? Strangely enough, App.test.tsx is indeed into the rootDir folder.

css-loader import css as modules

Here's an excerpt from my webpack.config.dev.js, helped by this little guide.

require.resolve('style-loader'),
{
  loader: require.resolve('css-loader'),
  options: {
    importLoaders: 1,
    modules: true,
    localIdentName: "[name]__[local]___[hash:base64:5]"
  },
},

That is the only change that I've made.

The problem I'm facing is that when I try using the css module imports I get an error like

(3,20): error TS2307: Cannot find module './Home.css'.

But, it works! I know this because if I reload the page, for a fraction of a second the style and page render correctly and then it spews that same error in the browser.

Home.tsx

import * as React from 'react';
import styles from './Home.css';

export default class Home extends React.Component {
  render () {
    return (
      <h1 className={styles.header}>Hello World!</h1>
    );
  }
}

Home.sass (which compiles to CSS with node-sass)

.header
  color: blue
  background-color: black

What does "change up" mean?

"and then change up our render call:

ReactDOM.render(
,
document.getElementById('root') as HTMLElement
);"

Do I replace the render function with above, if so do I not need to import ReactDOM?

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.