ReactとTypeScriptの使い方

  • 2024年10月17日
  • 2024年10月18日
  • 未分類
  • 11View
  • 0件

型定義

プリミティブ型の定義

// POINT プリミティブとは
// プリミティブとは、TypeScriptが扱うことの出来る基本的な値のこと
// 具体的な例としては、文字列、数値、巨大な数値、真偽値、null、undefinedなどがある

const Example = () => {
  //// プリミティブ型
  let str: string = 'hello';
  // 文字列に数字を入れると、エラーが発生する
  // str = 1;
  // console.log(str);

  let num: number = 100;
  // console.log(num);

  let bigNum: bigint = 100n;
  // console.log(bigNum);

  let bool: boolean = true;
  // console.log(bool);

  let nullish: null = null;
  // console.log(nullish);

  let undefinedValue: undefined = undefined;
  // console.log(undefinedValue);

  // リテラル型
  let trueVal: true = true;
  // trueのみ許容されている
  // trueVal = false;
  let num123: 123 = 123;
  let hello: 'hello' = 'hello';

  //// ユニオン型(複数の型を組み合わせて「型Tまたは型U」のような、「または」の意味を表すことができる)
  // T | U というように、|(パイプ) を用いてユニオン型を表す
  let strOrNum: string | number | boolean = 111;
  strOrNum = "hello";
  strOrNum = true;
  // console.log(strOrNum);

  // 文字列の「hello」かnumber型とboolean型のみ
  let helloOrNumOrBool: 'hello' | number | boolean = 111;

  // typeを使用して、変数として使用する
  type helloOrNum = 'hello' | number;
  const hello02: helloOrNum = "hello";

  // 見た目のために最初にパイプを使用しているが、無視される。
  type DayOfWeek =
    | 'Monday'
    | 'Tuesday'
    | 'Wednesday'
    | 'Thursday'
    | 'Friday'
    | 'Saturday'
    | 'Sunday'

  const day: DayOfWeek = "Sunday";

  //// 配列の型定義
  const array01: number[] = [1, 2, 3];
  const array02: string[] = ['test01', 'test02', 'test03'];
  // arrayコンストラクタを使用した配列の型定義
  const array03: Array<number> = [1, 2, 3];
  // 数字と文字列の配列
  const array04: (number | string)[] = [1, 'test02', 3];
  const array05: Array<number | string> = [1, 'test02', 3];

  //// オブジェクトの型定義
  const obj01: { name: string, age: number } = { name: 'Taro', age: 18 };
  type Person01 = { name: string, age: number };
  const obj02: Person01 = { name: 'Taro', age: 18 };
  // エラーになる
  // obj01.name = 18;
  // obj01.sex = 18;
  // const obj03: Person01 = { name: 'Taro' };
  // ageにクエスションマークを付与することで、ageを設定が不要になる
  type Person02 = { name: string, age?: number };
  const obj03: Person02 = { name: 'Taro' };

  //// オブジェクトと配列の定義
  const users: Person02[] = [
    { name: 'Taro' },
    { name: 'Hanako', age: 20 },
    { name: 'Jiro', age: 18 },
  ];
};

export default Example;

ユニオン型の定義

// POINT ユニオン型
// 複数の型を組み合わせて「型Tまたは型U」のような、「または」の意味を表すことができる
// T | U というように、|(パイプ) を用いてユニオン型を表す

const Example = () => {
  let strOrNum: string | number | boolean = 111;
  strOrNum = "hello";
  strOrNum = true;
  // console.log(strOrNum);

  // 文字列の「hello」かnumber型とboolean型のみ
  let helloOrNumOrBool: 'hello' | number | boolean = 111;

  // typeを使用して、変数として使用する
  type helloOrNum = 'hello' | number;
  const hello02: helloOrNum = "hello";

  // 見た目のために最初にパイプを使用しているが、無視される。
  type DayOfWeek =
    | 'Monday'
    | 'Tuesday'
    | 'Wednesday'
    | 'Thursday'
    | 'Friday'
    | 'Saturday'
    | 'Sunday'

  const day: DayOfWeek = "Sunday";
};

export default Example;

オブジェクト型の定義

const Example = () => {
  //// 配列の型定義
  const array01: number[] = [1, 2, 3];
  const array02: string[] = ['test01', 'test02', 'test03'];
  // arrayコンストラクタを使用した配列の型定義
  const array03: Array<number> = [1, 2, 3];
  // 数字と文字列の配列
  const array04: (number | string)[] = [1, 'test02', 3];
  const array05: Array<number | string> = [1, 'test02', 3];

  //// オブジェクトの型定義
  const obj01: { name: string, age: number } = { name: 'Taro', age: 18 };
  type Person01 = { name: string, age: number };
  const obj02: Person01 = { name: 'Taro', age: 18 };
  // エラーになる
  // obj01.name = 18;
  // obj01.sex = 18;
  // const obj03: Person01 = { name: 'Taro' };
  // ageにクエスションマークを付与することで、ageを設定が不要になる
  type Person02 = { name: string, age?: number };
  const obj03: Person02 = { name: 'Taro' };

  //// オブジェクトと配列の定義
  const users: Person02[] = [
    { name: 'Taro' },
    { name: 'Hanako', age: 20 },
    { name: 'Jiro', age: 18 },
  ];
};

export default Example;

関数の定義

const Example = () => {
  function sum01(x: number, y: number) {
    return x + y;
  }
  // 上記だと型推論で返り値がnumberになるが、下記だと返り値をnumberと設定する
  // function sum01(x: number, y: number): number {
  //   return x + y;
  // }
  console.log(sum01(1, 5));
  // アロー関数
  const sum02 = (x: number, y: number) => x + y;
  console.log(sum02(1, 8));
  // デフォルト値
  const sum03 = (x: number, y: number = 1) => x + y;
  console.log(sum03(1));
  // Nullを許容する
  function sum04(x: number, y?: number) {
    return y ? x + y: x;
  }
  console.log(sum04(2000));
  // voidは返り値がない(returnがない)
  const sum05 = (x: number, y: number): void => console.log(x + y);
  sum05(1000, 2000);

  // typeで型の設定
  type Sum = (x: number, y: number) => number;
  const sum06: Sum = (x, y) => x + y;
  console.log(sum06(1, 11));
};

export default Example;

コンポーネントとプロップスの定義

type HelloProps = {
  text: string,
  children?: React.ReactNode,
}
const Hello: React.FC<HelloProps> = (props) => {
  return <h1>Hello {props.text} {props.children}</h1>
};
// React.FCはコンポーネントを定義できる型です。
// React.FCがbooleanやstringのようなもの。
// コンポーネントでpropsを使用したい場合は、ジェネリクスを設定する
// https://qiita.com/kim_t0814/items/50d46b5f560831005ebc
// 上記参照
// 下記でも同じ実装ができる
// const Hello = (props: HelloProps) => {
//   return <h1>Hello {props.text} {props.children}</h1>
// };

type FnProps = {
  fn: (text: string) => void
}
export const Btn: React.FC<FnProps> = (props) => {
  return <button onClick={() => props.fn('TypeScript')}>ボタン</button>
};

export default Hello;
import Hello, { Btn } from "./Hello";

const Example: React.FC = () => {
    return (
      <>
        <Btn fn={(text) => console.log(`hello ${text}`)} />
        <Hello text="TypeScript">Children</Hello>
      </>
    );
};

export default Example;

ExampleコンポーネントにHelloファイルを呼び出している。

クラスの定義

class User {
  public name: string;
  // デフォルト値
  // public name: string = 'Hanako';
  public age: number;

  constructor(name: string, age: number) {
    this.name = name;
    this.age = age;
  }
}

const Example = () => {
  const user01 = { name: 'Hanako', age: 22 };
  const user02 = new User('Hanako', 24);
  // console.log(user02);
  return (
    <div>
      <p>name:{user02.name}</p>
      <p>age:{user02.age}</p>
    </div>
  )
};

export default Example;

useStateの定義

import { useState } from "react";

type Todo = {
  id: number;
  text: string;
};
type User = {
  name: string;
  age: number;
};

const Example = () => {
  const [ text, setText ] = useState('hello');
  useState(0);

  const [animals, setAnimals] = useState<string[]>(["dog", "cat"]);
  const [users, setUsers] = useState<User[]>([{ name: "Tom", age: 22 }]);
  const [todos, setTodos] = useState<Todo[]>([{ id: 100, text: '買い物' }]);
};

export default Example;

型推論

// POINT TypeScriptでは型推論(type inference)によって型をある程度推定してくれる機能がある
// 基本的には、明らかに型が分かるような場合の型定義は型推論に任せるようにする

const Example = () => {
  let str = 'hello';
  // 型推論でstrは文字列と判断されたため、下記はエラーになる
  // str = 123
  let obj = { name: 'Taro', age: 12 };

  const bye = 'bye';
  // constの場合は、リテラル型になるため、bye以外だとエラーになる
  // bye = 'test';
  const nmb = 123;
};

export default Example;

ジェネリクスについて

const Example = () => {
  const repeat = <T>(value: T, times: number): T[] => {
    return new Array(times).fill(value);
  }
  // 引数Tにそれぞれの型が入る
  // このように、型引数(type parameters)を受け取る関数を作る機能のことをジェネリクスと呼ぶ
  console.log(repeat<number>(10, 10));
  // (10) [10, 10, 10, 10, 10, 10, 10, 10, 10, 10]
  console.log(repeat<string>('test', 10));
  // (10) ['test', 'test', 'test', 'test', 'test', 'test', 'test', 'test', 'test', 'test']
  // 省略も可能
  console.log(repeat(1000, 10));
  console.log(repeat('test', 10));
};

export default Example;

TODOアプリの作成

import { useState } from "react";
import TaskList from "./TaskList";

export type Todo = {
  id: number;
  text: string;
};

const Example = () => {
  const [ inputText, setInputText ] = useState("");
  const [ todos, setTodos ] = useState<Todo[]>([
    { id: 0, text: '買い物' },
    { id: 1, text: '勉強' },
  ]);
  const changeHandler = (e: React.ChangeEvent<HTMLInputElement>) => setInputText(e.target.value);
  const addTodoIten = () => {
    setTodos(state => [...state, { id: todos.length, text: inputText }])
    setInputText("");
  }
  return (
    <>
      {/* <input type="text" value={inputText} onChange={(e) => setInputText(e.target.value)} /> */}
      <input type="text" value={inputText} onChange={changeHandler} />
      <button onClick={addTodoIten}>追加</button>
      <TaskList todos={todos}/>
    </>
  )
};

export default Example;
import React from "react";
import { Todo } from "./Example";

type TaskListProps = {
  todos: Todo[]
}

const TaskList: React.FC<TaskListProps> = ({todos}) => {
  return (
    <ul>
      {todos.map((todo) => {
        return <li key={todo.id}>{todo.text}</li>
      })}
    </ul>
  )
};

export default TaskList;

このようなイメージになります。