【React】TypeScript基礎

Reactは、今やJavaScriptでなく、TypeScriptで書くのが一般的になっています。

ReactでのTypeScriptの使用について、基礎をまとめました!

TypeScriptとは

JavaScriptに型という概念を組み込み、それにより、より安全に、バグが少なく開発できるメリットがある言語です。

そのため基本はJavaScriptと同じで、それに型の定義という概念を追加しただけのもの。

公式ドキュメントはこちら

The starting point for learning TypeScript
Find TypeScript starter projects: from Angular to React or Node.js and CLIs.

TypeScriptの使い方

TypeScriptの使用には、アプリ立ち上げの際に以下コマンドを実行します。

$ npx create-react-app プロジェクト名 --template typescript

末尾に–template typescriptを付けるだけ!

基本的な型

基本的な型の、それぞれの定義方法がこちら

// boolean
let bool: boolean = true;

// 数値
let num: number = 0;

// 文字
let str: string = "ABC"

// 配列
// 方法は2通りある
// 1. Arrayを使って型を指定
let arr1: Array<number> = [0, 1, 2];

// 2. 要素の型を指定して[]を付ける
let arr2: number[] = [0, 1, 2];

// どんな型でも入れられるany
let any1: any = false;

// null型
let null1: null = null;

// 何も設定されていないundefined
let undefined1: undefined = undefined

返却値の型指定

関数の引数に型を指定する場合、以下のように記述します。

  const calcTotalFee = (num: number): number => {
    const total = num * 1.1;
    console.log(total);
  };

変数の型指定

関数の中の変数に型を指定する場合、以下のように定義する。

  const onClickPractice = () => {
    let total: number = 0;
    total = getTotalFee(1000);
    console.log(total);
  };

設定tsconfig.json

TypeScriptの設定は、tsconfig.jsonファイルで行います。

create-react-appで立ち上げたときのデフォルトの設定がこちら

{
    "include": [
        "./src/**/*"
    ],
    "compilerOptions": {
        "strict": true,
        "esModuleInterop": true,
        "lib": [
            "dom",
            "es2015"
        ],
        "jsx": "react-jsx"
    }
}

“strict”: true とすることで厳しいルールをまとめて設定しています。

これにより、暗黙的な意味は許可しないといった働きをするため、型定義が必要になる。

デモデータの作成(TypeScriptとは無関係)

データ取得にはaxiosを使うと便利です。

axiosを使うことで、JSONデータの取得を簡単にすることができる。

$ npm install axios --save

JSONplaceholderのtodosを使う。

JSONPlaceholder - Free Fake REST API

axiosとjsonplaceholderを使って、ボタンクリックでtodoデータを取得するサンプルコードを作成

.thenで取得後の関数を指定できる。

import axios from "axios";
import "./styles.css";

export default function App() {
  const getFetchData = () => {
    axios.get("https://jsonplaceholder.typicode.com/todos").then((res) => {
      console.log(res);
    });
  };
  return (
    <div className="App">
      <button onClick={getFetchData}>データ取得</button>
    </div>
  );
}

useStateの型指定

以下のようにuseStateの後に<>の形で定義を記述します。

const [todos, setTodos] = useState<any>([]);

typeを使った型定義

TypeScriptでは、データ型が無いことによりバグることがある。

そのような型を定義するためには、typeを使ってTodoのアイテムの型定義をします。

type TodoType = {
  userId: number;
  id: number;
  title: string;
  complete: boolean;
};

受け取り側の記述

配列の型で取得するので、Arrayで指定し、<>には上記の型定義を指定

  const getFetchData = () => {
    axios.get<Array<TodoType>>("https://jsonplaceholder.typicode.com/todos").then((res) => {
      // console.log(res);
      setTodos(res.data);
    });
  };

setTodosで更新をしているので、useStateも同様に配列の型を定義する必要があります。

const [todos, setTodos] = useState<Array<TodoType>>([]);

propsの型定義

propsの型を、typeをを使って定義する。

type TodoType = {
  userId: number;
  title: string;
  completed: boolean;
}

export const Todo = (props: TodoType) => {
  const { title, userId, completed } = props;
  const completeMark = completed ? "[完]" : "[未]";
  return <p>{`${completeMark} ${title}(ユーザー:${userId})`}</p>;
};

親コンポーネント

      {todos.map((todo) => (
        <Todo title={todo.title} userId={todo.userId} completed={todo.complete}/>
      ))}

名前をTodoTypeとし、propsを型定義し、Appから受け取ったpropsを表示している。

型定義の効率化

上記で、Todoコンポーネントの型と、propsの型に同じような型を定義しました。

このような同じような型は共通化してまとめることができます。

src > typesディレクトリを作成し、todo.tsファイルを作成する。

そこにtypeを移換

export type TodoType = {
  userId: number;
  id: number;
  title: string;
  complete: boolean;
};

移換元のAppとTodo.tsxでimportを記述

import { TodoType } from "./types/todo"

ただこの2つは全く一緒ではなく、Todo.tsxにはidが不要であるため、要不要を指定できる処理を加える必要があります。

方法は2つ

pickを使用する(必要なプロパティを選択する)方法

抜き出すものを型名とプロパティ名で指定する。

export const Todo = (props: Pick<TodoType, "userId" | "title" | "completed">) => {

上記の場合、userIdとtitle、completedを抜き出している。

omitを使用する(不要なプロパティを選択する)方法

2つ目の方法としては、逆に除くのもを指定することもできる。

export const Todo = (props: Omit<TodoType, "id">) => {

コンポーネント自体の型定義

関数コンポーネントの型を指定するには、FCを使用します。

import { FC } from "react"

type Props = {
  color: string;
  fontSize: string;
}

export const Text: FC<Props> = (props) => {

引数が無い場合、voidを使って以下のように記述する。

例えば関数colorの引数なし、返却値なしの場合

type Props = {
  color: () => void
}

オプショナルチェイニング

?を付け、それ以降のデータを探しに行くかどうかを指定できる。

{user.hobbies?.join(" / ")}

この場合、user.hobbiesの値が無ければ、その時点でundefinedが返される。

オプショナルチェイニングの?を付けていない場合、joinで値の取得ができずエラーとなってしまう。

これを防ぐことができる。

以上、読んでいただきありがとうございました。

コメント