React & TypeScript
Installation
See the section
Create New TypeScript Project
in Project Setup.We will use the
my-app
project we created with TypeScript enabled usingCreate React App
.
Props
Function Component
- Create the file
src\Hello.tsx
. - Create a function component.
src\Hello.tsx
import 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("!");
}
- Render
<Hello />
component in the App component.
src\App.tsx
import React from 'react';
- import logo from './logo.svg';
import './App.css';
import Hello from './Hello';
const App: React.FC = () => {
return (
<div className="App">
- <header className="App-header">
- <img src={logo} className="App-logo" alt="logo" />
- <p>
- Edit <code>src/App.tsx</code> and save to reload.
- </p>
- <a
- className="App-link"
- href="https://reactjs.org"
- target="_blank"
- rel="noopener noreferrer"
- >
- Learn React
- </a>
- </header>
+ <Hello />
</div>
);
};
export default App;
- You will get the following TypeScript error.
Property 'name' is missing in type '{}' but required in type 'Props'.
- Add
name
as aprop
.
src\App.tsx
...
- <Hello ></Hello>
+ <Hello name="David"></Hello>
...
- The compiler error will go away and following should be displayed in the browser.
Hello David!
Enthusiasm level is an nullable parameter so we did not have to set it yet. Set enthusiasm level as follows and observe the results:
<Hello name="David" enthusiasmLevel="3"></Hello>
- Type 'string' is not assignable to type 'number | undefined'
<Hello name="David" enthusiasmLevel={3}></Hello>
- Hello David!!!
<Hello name="David" enthusiasmLevel={0}></Hello>
- Error: You could be a little more enthusiastic. :D
- Change it back so the error goes away:
<Hello name="David" enthusiasmLevel={3}></Hello>
Class Component
- Replace
Hello
with a similar implementation that uses a class component.
src\Hello.tsx
import React from "react";
export interface Props {
name: string;
enthusiasmLevel?: number;
}
class Hello extends React.Component<Props> {
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>
);
}
}
export default Hello;
// helpers
function getExclamationMarks(numChars: number) {
return Array(numChars + 1).join("!");
}
- Verify the component works as it did before.
State
- Replace
Hello
with the new implementation below that stores enthusiasm level asstate
.
src\Hello.tsx
import React from "react";
export interface Props {
name: string;
enthusiasmLevel?: number;
}
interface State {
currentEnthusiasm: number;
}
class Hello extends React.Component<Props, State> {
state = { currentEnthusiasm: this.props.enthusiasmLevel || 1 };
onIncrement = () => {
this.updateEnthusiasm(1);
};
onDecrement = () => {
this.updateEnthusiasm(-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(change: number) {
this.setState((currentState) => {
return { currentEnthusiasm: currentState.currentEnthusiasm + change };
});
}
}
export default Hello;
function getExclamationMarks(numChars: number) {
return Array(numChars + 1).join("!");
}
- Notice that
state
is the second type parameter being passed when the class is constructed.
You can leave
state
off if the component doesn't have local state.
class Hello extends React.Component<Props>
class Hello extends React.Component<Props, State>
If you have state but no props use one of the following syntaxes.
class Hello extends React.Component<object, State>
class Hello extends React.Component<any, State>
class Hello extends React.Component<{}, State>
- Set
enthusiasmLevel
as aprop
.
src\App.tsx
import React from 'react';
import './App.css';
import Hello from './Hello';
const App: React.FC = () => {
return (
<div className="App">
<Hello name="Evis"
+ enthusiasmLevel={2}
></Hello>
</div>
);
};
export default App;
- Verify the component is working.
Event Handlers
- Replace
Hello
with the new implementation below that strongly types the event object.
This enables autocomplete for methods or properties on the event and type errors when you attempt to access a non-existent property or invoke an invalid function.
src\Hello.tsx
import React, { SyntheticEvent } from "react";
export interface Props {
name: string;
enthusiasmLevel?: number;
}
interface State {
currentEnthusiasm: number;
}
class Hello extends React.Component<Props, State> {
state = { currentEnthusiasm: this.props.enthusiasmLevel || 1 };
onIncrement = (event: SyntheticEvent) => {
console.log(event);
this.updateEnthusiasm(1);
};
onDecrement = (event: SyntheticEvent) => {
console.log(event.target);
this.updateEnthusiasm(-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(change: number) {
this.setState((currentState) => {
return { currentEnthusiasm: currentState.currentEnthusiasm + change };
});
}
}
export default Hello;
function getExclamationMarks(numChars: number) {
return Array(numChars + 1).join("!");
}