- Class Components
- Typing getDerivedStateFromProps
- TypeScript and React: Components
- Functional components #
- Class components #
- constructors #
- defaultProps #
- Bottom line #
- React Typescript — Class Components
- Create Typescript Class Component in React
- Passing properties to class components in typescript
- Class methods and properties in typescript
- Class Components features
Class Components
Within TypeScript, React.Component is a generic type (aka React.Component ), so you want to provide it with (optional) prop and state type parameters:
type MyProps = // using `interface` is also ok message: string; >; type MyState = count: number; // like this >; class App extends React.ComponentMyProps, MyState> state: MyState = // optional second annotation for better type inference count: 0, >; render() return ( div> this.props.message> this.state.count> div> ); > >
Don’t forget that you can export/import/extend these types/interfaces for reuse.
Why annotate state twice?
It isn’t strictly necessary to annotate the state class property, but it allows better type inference when accessing this.state and also initializing the state.
This is because they work in two different ways, the 2nd generic type parameter will allow this.setState() to work correctly, because that method comes from the base class, but initializing state inside the component overrides the base implementation so you have to make sure that you tell the compiler that you’re not actually doing anything different.
You often see sample code include readonly to mark props and state immutable:
type MyProps = readonly message: string; >; type MyState = readonly count: number; >;
This is not necessary as React.Component already marks them as immutable. (See PR and discussion!)
Class Methods: Do it like normal, but just remember any arguments for your functions also need to be typed:
class App extends React.Component message: string >, count: number >> state = count: 0 >; render() return ( div onClick=() => this.increment(1)>> this.props.message> this.state.count> div> ); > increment = (amt: number) => // like this this.setState((state) => ( count: state.count + amt, >)); >; >
Class Properties: If you need to declare class properties for later use, just declare it like state , but without assignment:
class App extends React.Component message: string; >> pointer: number; // like this componentDidMount() this.pointer = 3; > render() return ( div> this.props.message> and this.pointer> div> ); > >
Typing getDerivedStateFromProps
Before you start using getDerivedStateFromProps , please go through the documentation and You Probably Don’t Need Derived State. Derived State can be implemented using hooks which can also help set up memoization.
Here are a few ways in which you can annotate getDerivedStateFromProps
- If you have explicitly typed your derived state and want to make sure that the return value from getDerivedStateFromProps conforms to it.
class Comp extends React.ComponentProps, State> static getDerivedStateFromProps( props: Props, state: State ): PartialState> | null // > >
class Comp extends React.Component Props, ReturnTypetypeof Comp["getDerivedStateFromProps"]> > static getDerivedStateFromProps(props: Props) > >
type CustomValue = any; interface Props propA: CustomValue; > interface DefinedState otherStateField: string; > type State = DefinedState & ReturnTypetypeof transformPropsToState>; function transformPropsToState(props: Props) return savedPropA: props.propA, // save for memoization derivedState: props.propA, >; > class Comp extends React.PureComponentProps, State> constructor(props: Props) super(props); this.state = otherStateField: "123", . transformPropsToState(props), >; > static getDerivedStateFromProps(props: Props, state: State) if (isEqual(props.propA, state.savedPropA)) return null; return transformPropsToState(props); > >
TypeScript and React: Components
Components are at the heart of React. Let’s see what we can do to get better error handling and tooling for them!
Functional components #
Functional components are my most favourite thing in React. They are simple, purely functional and super easy to reason about. The following shows an example of a functional component with some typed properties.
import React from 'react'; // we need this to make JSX compile
type CardProps =
title: string,
paragraph: string
>
export const Card = ( title, paragraph >: CardProps) => aside>
h2> title >/h2>
p>
paragraph >
/p>
/aside>
const el = Card title="Welcome!" paragraph="To this example" />
We use as little TypeScript as possible. Creating a type for our properties, and telling TypeScript that the parameters of our functional component are of that type. You already get nice suggestions in VS Code:
And errors when you compile without passing all required properties:
If you want to make some properties optional, do that in the respective Props type:
type CardProps =
title: string,
paragraph?: string // the paragraph is optional
>
There’s a generic type you can use.
import React, FunctionComponent > from 'react'; // importing FunctionComponent
type CardProps =
title: string,
paragraph: string
>
export const Card: FunctionComponentCardProps> = ( title, paragraph >) => aside>
h2> title >/h2>
p>
paragraph >
/p>
/aside>
const el = Card title="Welcome!" paragraph="To this example" />
The parameters of our function are infered from the generic FunctionComponent. Other than that, it seems very similar to the first example. However, it allows for optional child components:
type CardProps =
title: string,
paragraph: string
>
// we can use children even though we haven't defined them in our CardProps
export const Card: FunctionComponentCardProps> = ( title, paragraph, children >) => aside>
h2> title >/h2>
p>
paragraph >
/p>
children >
/aside>
More on the usage of child components in Children.
Class components #
One of the things that convinced me to use React were functional components. The “olde way” of doing components is with class components. And they can keep state per class. State is like props, but private and only controlled by the component.
@types/react typings of course have full support for those, and are also equally easy to use.
Class components need to be extended from the base React.Component class. Typings enhance this class with generics, passing props (like FunctionComponent earlier) and state. Let’s do a clock component:
import React, Component > from 'react'; // let's also import Component
// the clock's state has one field: The current time, based upon the
// JavaScript class Date
type ClockState =
time: Date
>
// Clock has no properties, but the current state is of type ClockState
// The generic parameters in the Component typing allow to pass props
// and state. Since we don't have props, we pass an empty object.
export class Clock extends Component>, ClockState>
// The tick function sets the current state. TypeScript will let us know
// which ones we are allowed to set.
tick()
this.setState(
time: new Date()
>);
>
// Before the component mounts, we initialise our state
componentWillMount()
this.tick();
>
// After the component did mount, we set the state each second.
componentDidMount()
setInterval(() => this.tick(), 1000);
>
// render will know everything!
render()
return p>The current time is this.state.time.toLocaleTimeString()>/p>
>
>
And through proper tooling, we get a ton of infos:
First, setState is aware of its state properties and only allows to set those. Even if you have more state properties, TypeScript allows you to only set those you want to update.
When we access state in our render function, we have access to all its properties. Here we see time , and it’s of type Date
Date of course is a built-in JavaScript type, so we get full access to all its methods. Ever wanted to know what Date can do? Let TypeScript tell you:
That’s a lot of tooling support, just for a couple of keystrokes more. The type inference of React does the rest.
constructors #
The constructor function is a bit special. You need to pass your props there (even if you don’t have any), and TypeScript requires you to pass the to the super constructor function.
However, when writing the typical pattern of constructors and super calls in TypeScript’s strict mode, you will get an error if you don’t provide any typings yourself. This is because you create a new class, with a completly new constructor, and TypeScript does not know which parameters to expect!
Therefore, TypeScript will imply them to be any . And implicit any in strict mode is not allowed.
export class Sample extends ComponentSampleProps>
constructor(props) // ️⚡️ does not compile in strict mode
super(props)
>
>
Even though the super call knows which props to expect, we need to be explicit with our constructor function:
export class Sample extends ComponentSampleProps>
constructor(props: SampleProps)
super(props)
>
>
defaultProps #
Default properties allow you to specifcy default values for properties. In case you don’t want to have every value to be set explicitly. React has the property defaultProps reserved for components.
TypeScript in version 3.0 is honouring defaultProps . With the latest React typings (v 16.4.8) you are ready to go:
import React, Component > from 'react';
type NoticeProps =
msg: string
>
export class Notice extends ComponentNoticeProps>
static defaultProps =
msg: 'Hello everyone!'
>
render()
return p> this.props.msg >/p>
>
>
const el = Notice /> // Will compile in TS 3.0
For FunctionComponents, I suggest using the ES6 default value syntax and optional type properties:
type CardProps =
title: string,
paragraph?: string // the paragraph is optional
>
// No need to define the defaultProps property
export const Card: FunctionComponentCardProps> = ( title, paragraph = 'Hello World' >) =>
aside>
h2> title >/h2>
p>
paragraph >
/p>
/aside>
Bottom line #
You already can see that you don’t have to write that many typings or boilerplate code in React to get into the nice tooling and type safety features of TypeScript. Components are a huge deal in React, and with just a couple of keystrokes we have everything we need.
Let’s see what else we can do in the next section.
React Typescript — Class Components
How to create class components and define state and props and pass data to component class methods and instance properties declare in React Typescript with examples of stateful typescript component.
In React, Everything is a UI Component that can be created using reusable class or functional Components.
Class Components: are also called stateful components, maintain a state of a user. Functional Components: these are also called stateless components, and do not maintain the state of a user.
The state and prop are two types in ReactJS for data passing and storage types.
Class components are created using ES6 class syntax.
Create Typescript Class Component in React
Let’s create Simple Class components.
from 'react'; class ClassComponent extends Component < render() < return ( Hello World ); > > export default ClassComponent;
In typescript, React components extends React.Component . React.Component is a Generic class, an alias for React.Component .
PropType and StateType are optional new types that hold the state and props of a React Component.
It can be created using type or interface in typescript and exported to use in another component.
It also contains a render function that returns data from a component.
Passing properties to class components in typescript
Let’s create a state and props in Typescript
Props contains a counter of type number that gets passed from the parent component and private to the class.
state contains numbers type that that stored in a component and the available public to class.
Both can also be created using the interface in typescript for type safety.
Here is a class component
from 'react'; //props object type Numbers= < counter:number; >//state object type Result= < number:number; >class ClassComponent extends Component < state: Result = < number: 0, >; componentDidMount() < this.setState((state) =>(< number: state.number + this.props.counter, >)); > render() < return ( Hello World - ); > > export default ClassComponent;
how do you pass props from parents in typescript? Like normal components, data can be passed to the component using the below syntax
React Typescript Examples
>