ref – https://blog.logrocket.com/using-typescript-with-react-tutorial-examples/
The key to TypeScript is that it’s a statically typed script. Programming languages can either be statically or dynamically typed; the difference is when type checking occurs. Static languages variables are type-checked.
TypeScript allows you to define complex type definitions in the form of interfaces. This is helpful when you have a complex type that you want to use in your application, such as an object which contains other properties. This results in strict checks, which reduces the number of possible bugs you might have produced without it.
JSX stands for JavaScript XM. It allows us to write HTML code directly in our React project. Using TypeScript with React provides better IntelliSense, code completion for JSX.
Basic Setup
mkdir typescript-react-project
cd typescript-react-project
npm init
How does TypeScript compile React code?
TypeScript always checks for a file called tsconfig.json in the project root folder for instructions. When it finds the tsconfig.json file, it loads the settings defined in the file and uses them to build the project.
A TypeScript project is compiled in one of the following ways:
By invoking tsc with no input files, in which case the compiler searches for the tsconfig.json file starting in the current directory and continuing up the parent directory chain.
By invoking tsc with no input files and a –project (or just -p) command line option that specifies the path of a directory containing a tsconfig.json file, or a path to a valid .json file containing the configurations
touch tsconfig.json
1 2 3 4 5 6 7 8 9 10 11 |
{ "compilerOptions": { "outDir": "./dist/", "noImplicitAny": true, "module": "es6", "target": "es5", "jsx": "react", "allowJs": true, "moduleResolution": "node", } } |
The JSON configuration above defines two major sections: the compilerOptions and exclude parameters.
In the compilerOptions, a target of es6 has been set. This means the JavaScript engine target will be set to es6 but will compile down to es5 as the target.
Notice that there is also a key called jsx, which is set to react. This tells TypeScript to compile JSX files as React files. This is similar to running tsc –jsx react.
The outDir is the output folder after compilation.
In the exclude block, node_modules is being defined for it. TypeScript will not scan the node_modules folder for any TypeScript file while compiling.
If you’re familiar with TypeScript and its configuration, you might wonder why the include section is missing. This is because we’re going to configure webpack to handle taking in the entry files, passing them to TypeScript for compilation, and returning a bundled JavaScript script for browsers.
Configuring Webpack
npm install webpack webpack-cli ts-loader
What is ts-loader?
As its name implies, ts-loader is the TypeScript loader for webpack. Put simply, it’s a plugin that helps webpack work well with TypeScript.
Just like TypeScript, webpack also checks for a file called webpack.config.js for configuration.
If it doesn’t already exist, create a new file called webpack.config.js and add the following code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
const path = require('path'); module.exports = { mode: 'development', entry: './src/index.tsx', module: { rules: [ { test: /\.tsx?$/, use: 'ts-loader', exclude: /node_modules/, }, ], }, resolve: { extensions: ['.tsx', '.ts', '.js'], }, output: { filename: 'bundle.js', path: path.resolve(__dirname, 'dist'), }, }; |
Adding npm scripts
In your package.json, edit your scripts attribute like so:
1 2 3 4 5 6 7 8 9 10 11 12 |
{ "name": "typescript-react-project", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1", "magic": "webpack" }, ... ... } |
After all the configurations were done above, it’s time to create the main entry point file of our project, but before we do that, we need to install types definition for libraries installed.
npm install react react-dom @types/react @types/react-dom
Next, create a new folder src and then a file in the src folder called index.tsx in the root and add the following code:
1 2 3 4 5 6 7 8 |
import * as React from "react"; import * as ReactDOM from "react-dom"; ReactDOM.render( <div> <h1>Hello, Welcome to React and TypeScript</h1> </div>, document.getElementById("root") ); |
Above is a simple React setup, except that it is using TypeScript. To compile the file, run the command below in your terminal:
npm run magic
A build folder with a file named bundle.js has been created.
Does this newly created bundle work as expected? Create a new index.html file that references the new build to find out:
1 2 3 4 5 6 7 8 9 10 11 12 |
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Getting Started with Typescript and ReactJS</title> </head> <body> <!-- this is where react renders into --> <div id="root"></div> <script src="dist/bundle.js"></script> </body> </html> |
double click on index.html and you should see a simple page appear.
Creating React components in TypeScript
src/component/FirstComponent.tsx
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
import * as React from "react"; let Logo ="https://logrocket-assets.io/static/home-hero-c97849b227a3d3015730e3371a76a7f0.svg"; export default class FirstComponent extends React.Component <{}> { render() { return ( <div> <h3>A Simple React Component Example with Typescript</h3> <div> <img height="250" src={Logo} /> </div> <p>This component shows the Logrocket logo.</p> <p>For more info on Logrocket, please visit https://logrocket.com </p> </div> ); } } |
To make this new component accessible to React, we need to import and use the component in the base index.tsx file. Update the index.tsx file to:
1 2 3 4 5 6 7 8 9 10 11 |
import * as React from "react"; import * as ReactDOM from "react-dom"; import FirstComponent from './components/FirstComponent' ReactDOM.render( <div> <h1>Hello, Welcome to React and TypeScript</h1> <FirstComponent/> </div>, document.getElementById("root") ); |
npm run magic
output:
Using TypeScript interfaces with React components
One of TypeScript’s core principles is that type checking focuses on the shape that values have. This is sometimes called “duck typing” or “structural subtyping.”
In TypeScript, interfaces fill the role of naming these types and are a powerful way of defining contracts within your code and contracts with code outside of your project.
To see how you can use interfaces with your react components, create a file src/UserInterface.ts in the src folder and add the following code:
1 2 3 4 5 6 |
export default interface User{ name: string; age: number; address: string; dob: Date; } |
The code block above defines a simple User interface, which will be passed in as props into a new component. Because this interface is strongly typed, notice you cannot pass an integer for the name key, as the value is a string.
Create a new component in our components folder called UserComponent.tsx and add the following code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
import * as React from "react"; import UserInterface from '../UserInterface' export default class UserComponent extends React.Component<UserInterface, {}> { constructor (props: UserInterface){ super(props); } render() { return ( <div> <h1> User Component</h1> Hello, <b>{this.props.name}</b> <br/> You are <b>{this.props.age} years old</b> <br/> You live at: <b>{this.props.address}</b> <br/> You were born: <b>{this.props.dob.toDateString()}</b> </div> ); } } |
The UserInterface created earlier on has been imported and passed down as the props of the UserComponent. In the constructor, we checked that the props passed are of the UserInterface type and in the render function, the data will be displayed on our page.
After creating our UserComponent, update the index.tsx file:
1 2 3 4 5 6 7 8 9 10 11 12 |
import * as React from "react"; import * as ReactDOM from "react-dom"; import FirstComponent from './components/FirstComponent' import UserComponent from './components/UserComponent' ReactDOM.render( <div> <h1>Hello, Welcome to React and TypeScript</h1> <FirstComponent/> <UserComponent name="John Doe" age={26} address="87 Summer St, Boston, MA 02110" dob={new Date()} /> </div>, document.getElementById("root") ); |
npm run magic