“This is the fifth day of my participation in the November Gwen Challenge. See details of the event: The Last Gwen Challenge 2021”.

React + Hook + TS: TypeScript with React + Hook This article focuses on the pitfalls I encountered in TypeScript writing in my demo.

Demo address: “TS-todo”

1. Create the TS project

Create a React project with create-react-app. Add typescript configuration when creating a React project:

npx create-react-app app-name --template typescript
Copy the code

2. React Hook TS

Change the name of all.js files to.ts and all.jsx files to.tsx. If you still use JavaScript, the project will still run, but if you configure TypeScript to write JavaScript, you won’t be able to practice!

In the process of writing the demo, I encountered the following pits, which were solved after searching. This is to record.

1. Function components

To use React Hook, we need to write a function component. We need to tell TypeScript that the function is a React component. In JavaScript, we usually define a function component like this:

const App = () = > {
    return <>App</>;
};
Copy the code

When TypeScript is configured, function types need to be added. React provides the react. FunctionComponent type, which stands for FunctionComponent. We can simply write react. FC, as shown in the following code:

const App: React.FC = () = > {
    return <>App</>;
};
Copy the code

2. Type declaration examples

For simple type declarations, such as number, string, and Boolean, simply add :[type] after the declared variable.

For example, define an age of type number and an isDone of type Boolean:

let age: number = 37;
let isDone: boolean = false;
Copy the code

In writing the demo, I used an array of objects with the following structure:

[{id: 'xxxx'.content: 'xxxxxxx'.isDone: false },
    { id: 'xxxx'.content: 'xxxxxxx'.isDone: false },
    { id: 'xxxx'.content: 'xxxxxxx'.isDone: false},]Copy the code

We need to define another interface:

interface TaskObj {
    id: string;
    content: string;
    isDone: boolean;
}
Copy the code

Note: Interface names usually start with a capital letter.

This interface indicates that the object defined must satisfy the following conditions:

  • There areidProperty and of typestring
  • There arecontentProperty and of typestring
  • There areisDoneProperty and of typeboolean

TypeScript does not check the order of attributes, as long as they exist and are typed.

To define a single object, we can use the interface we just defined:

const obj: TaskObj = { id: 'xxxx'.content: 'xxxxxxx'.isDone: false };
Copy the code

But if you want to define the above array of objects, you would write:

const allTasks: TaskObj[] = [
    { id: 'xxxx'.content: 'xxxxxxx'.isDone: false },
    { id: 'xxxx'.content: 'xxxxxxx'.isDone: false },
    { id: 'xxxx'.content: 'xxxxxxx'.isDone: false},];Copy the code

TaskObj[] indicates that the type is an array, and the elements in the array must satisfy the TaskObj interface.

3. useState

For storing string state, add

to the right of useState:

const [input, setInput] = useState<string> (' ');
Copy the code

In fact, useState

(” “) already gives the initial value “, so TypeScript automatically determines the type, even if

is not written.

If the data structure to be stored is as follows:

[{id: 'xxxx'.content: 'xxxxxxx'.isDone: false },
    { id: 'xxxx'.content: 'xxxxxxx'.isDone: false },
    { id: 'xxxx'.content: 'xxxxxxx'.isDone: false},]Copy the code

So we still need the interface mentioned above:

interface TaskObj {
    id: string;
    content: string;
    isDone: boolean;
}

const [task, setTask] = useState<TaskObj[]>([]);
Copy the code

4. The parent component sends parameters to the child component

In JavaScript, the parent component passes parameters to the child component, which is written to the child component and received by the child component via props:

<Doing doing={doing} setTask={setTask} />
Copy the code

However, TypeScript does this because the child component doesn’t have an interface for passing parameters and needs to define its own interface.

As shown in the code above, in addition to the sub-component Doing, we need to specify an interface that meets the requirements of passing parameters:

interface DoingProps {
    doing: TaskObj[];
    setTask: Function;
}

const Doing: React.FC<DoingProps> = ({ doing, setTask }) = >{... }Copy the code

In the preceding code, an interface for DoingProps is defined, and

is added to the react. FC of the subcomponent. The parameters received by the subcomponent must meet the following requirements:

  • There aredoingProperty and is of type array. The elements of array satisfy theTaskObjInterface.
  • There aresetTaskProperty, and the type is a function.

In this way, the process of a parent component passing parameters to a child component is implemented in TypeScript.

Type assertion

In the demo, we need to get the DOM node of the input field, and write the following code:

const inputNode: HTMLInputElement = document.getElementById(`${id}`)
Copy the code

TypeScript displays the following error:

We simply add a type assertion that explicitly tells the compiler the type of the variable:

const inputNode: HTMLInputElement = document.getElementById(`${id}`) as HTMLInputElement;
Copy the code

6. Keyboard events

To determine which key was pressed, we need a KeyboardEvent object, written in TypeScript. We need to introduce the KeyboardEvent first:

import { KeyboardEvent } from 'react';
Copy the code

When passing an event object parameter, specify it as a keyboard event:

<input 
    type="text" 
    defaultValue="{obj.content}" 
    onKeyDown={(e: KeyboardEvent) = > updateTask(e, obj.id, obj.content)}
/>
Copy the code

The updateTask function is defined as follows:

const updateTask = (e: KeyboardEvent, id: string, oldContent: string) = >{... }Copy the code