Open8

TypeScript入門

どるあがどるあが

厳密な型指定

TypeScriptはjavaScriptに型指定を導入してくれる
型指定が無いのはいいこともあれば悪いこともある

typeList.tsx
/* eslint-disable */

/** TypeScriptの基本の型 */

// boolean
let bool: boolean = true;

// number 数値
let num: number = 0;

// string 文字
let str: string = "A";

// array 配列
let arr1: Array<number> = [0, 1, 2];
let arr2: number[] = [0, 1, 2];

// tuple
let tuple: [number, string] = [0, "A"];

// any なんでも良い
let any1: any = false;

// void 関数
// 何も書かなければvoidと認識する
const funcA = (): void => {
  const test = "TEST";
};

// null
let null1: null = null;

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

// object
let obj1: object = {};
let obj2: { id: number; name: string } = { id: 0, name: "name" };
どるあがどるあが

つまり?

これはエラーにならない

しかし、以下のようにcalcTotalFeeの引数に型指定を与えることによって、文字列を渡そうとしている部分でエラーが起きている。これは厳密な型指定のお陰なのだ。のだのだ。

どるあがどるあが

戻り値の型を決めよう

引数の後に: numberなどとして指定する
画像のように、returnの型をstringにしようとするとエラーが起きる

どるあがどるあが

変数の型を指定する

let total: numberと型をnumberにしてるので、total.toStringが返ってきて代入しようにもエラーになっている

どるあがどるあが

型定義

TypeScriptの真骨頂、型定義!!
取得するデータに応じてこのような型を定義する

App.tsx
type TodoType = {
  userId: number;
  id: number;
  title: string;
  completed: boolean;
};

stateで以下のように型を指定できる。
今回データが複数配列形式で渡されるので、Array<TodoType>という型になっているのに気を付ける

App.tsx
  const [todoes, setTodoes] = useState<Array<TodoType>>([]);

propsに型を指定することで、不要なバグを防ぐことができるようになる。
型名の後ろに?を付ければ、変数が渡されなくてもエラーにならない。そのため初期値を設定しておくのが良い

Todo.tsx
type TodoType = {
  userId: number;
  title: string;
  completed?: boolean; //指定しなくてもエラーにならない
};

export const Todo = (props: TodoType) => {
  // completedは渡ってこなくてもいいので初期値を設定しておく
  const { title, userId, completed = false } = props;
  const completaMark = completed ? "[完]" : "[未]";
  return <p>{`${completaMark}${title}(ユーザー:${userId})`}</p>;
};

どるあがどるあが

型定義の管理

他と同じように別ファイルに切り出せる

Todo.tsx
import { TodoType } from "./types/todo";

型をそのまま使いたくない時は、Pick,Omitというものを使える。既存の型から抽出したり省略して記述できる。

  // Pick:型の中から抽出して型を使用できる
  props: Pick<TodoType, "userId" | "title" | "completed">
  // Omit:型の中から省略して型を使用できる
  props: Omit<TodoType, "id">

全文

Todo.tsx
export const Todo = (
  // Pick:型の中から抽出して型を使用できる
  // props: Pick<TodoType, "userId" | "title" | "completed">
  // Omit:型の中から省略して型を使用できる
  props: Omit<TodoType, "id">
) => {
  // completedは渡ってこなくてもいいので初期値を設定しておく
  const { title, userId, completed = false } = props;
  const completaMark = completed ? "[完]" : "[未]";
  return <p>{`${completaMark}${title}(ユーザー:${userId})`}</p>;
};

どるあがどるあが

関数の型指定 VFC※ver 17

Text.tsx
import { VFC } from "react";

// ここはいつものtype指定
type Props = {
  color: string;
  fontSize: string;
};

// 関数コンポーネントにはVFCを使う ※ver17
// ver18以降ではFCで良くなる。ver17ではchildrenが暗黙的に持ってしまっている
// 関数名: VFC<型>
export const Text: VFC<Props> = (props) => {
  const { color, fontSize } = props;
  return <p style={{ color, fontSize }}>テキストです</p>;
};

どるあがどるあが

OptionalChaining

配列に要素が無い場合、エラーにしないことができる

UserProfile.tsx
type Props = {
  user: User;
};

export const UserProfile: VFC<Props> = (props) => {
  const { user } = props;
  return (
    <dl>
      <dt>名前</dt>
      <dd>{user.name}</dd>
      <dt>趣味</dt>
      {/* 配列.join(デミリタ)で、配列をデミリタで接続してストリングにする */}
      {/* OptionalChaining 配列に?をつけると、要素が無い場合エラーにならず
      そのまま終了する。以下の例だとhobbiesを渡さない場合何も表示されない。 */}
      <dd>{user.hobbies?.join(" / ")}</dd>
    </dl>
  );
};

hobbiesがある場合
const user: User = {
  name: "asdfajslfjals",
  hobbies: ["telnet", "bombealdhie"]
};

hobbiesがない場合
const user: User = {
  name: "asdfajslfjals",
  // hobbies: ["telnet", "bombealdhie"]
};

使い方
<UserProfile user={user} />