TypeScriptの基本的なところを備忘として残しておく
はじめに
最近、Type Script を学び始めたのでその基本的なところの備忘録となります。
TypeScript とは
- Microsoft が開発したオープンソースの言語
- JavaScript に「型」という概念
- より安全にバグが少なく開発できる
- 開発者間で認識を合わせやすい
- エディタでのコード補完も効くので開発効率が上がる
- コンポーネント指向の React と非常に相性が良い
基本的な型
/** Typescriptの基本の型 */
// boolean 真偽値
let bool: boolean = true;
// number 数値
let num: number = 0;
// string 文字
let str: string = "ABC";
// Array 配列
let arr1: Array<number> = [0, 1, 2];
let arr2: number[] = [0, 1, 2];
// tuple 複数の値を保持
let tuple: [number, string] = [0, "ABC"];
// any 型指定無し
let any1: any = false;
// 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: "ABC" };
引数の型指定
引数に型指定すると、calcTotalFee(1000)で calcTotalFee("1000")のように文字を入力すると、エディタ上で型が違うことを示してくれる。
また、その際に何の型が入るのかも分かる。
export const Practice1 = () => {
const calcTotalFee = (num: number) => {
const total = num * 1.1;
console.log(total);
};
const onClickPractice = () => calcTotalFee(1000);
return (
<div>
<p>練習問題1:引数の型指定</p>
<button onClick={onClickPractice}>練習問題1を実行</button>
</div>
);
};
返却値の型指定
返却値の型指定を行うと、return で返すものにも型を指定することができる。
export const Practice2 = () => {
const getTotalFee = (num: number): number => {
const total = num * 1.1;
return total;
};
const onClickPractice = () => {
console.log(getTotalFee(1000));
};
return (
<div>
<p>練習問題:返却値の型指定</p>
<button onClick={onClickPractice}>練習問題2を実行</button>
</div>
);
};
変数の型指定
export const Practice3 = () => {
const getTotalFee = (num: number): number => {
const total = num * 1.1;
return total;
};
const onClickPractice = () => {
let total: number = 0;
total = getTotalFee(1000);
console.log(total);
};
return (
<div>
<p>練習問題:変数の型指定</p>
<button onClick={onClickPractice}>練習問題3を実行</button>
</div>
);
};
tsconfig 設定について
tsconfig 設定を変更することで、もっと厳し目のルールで行いたい、ここのエラーは表示しなくて良い等、プロジェクトに合わせた設定を行うことができる。
"strict": true
"strict": true とすることで、厳し目のルールを予め設定してくれる。
{
"include": [
"./src/**/*"
],
"compilerOptions": {
"strict": true,
"esModuleInterop": true,
"lib": [
"dom",
"es2015"
],
"jsx": "react-jsx"
}
}
これを設定しておくと、以下のようなコードの場合に
const calcTotalFee = (num) => {
const total = num * 1.1;
console.log(total);
};
「num」に型が、暗黙的に「any」になっていると教えてくれるようになる。
Parameter 'num' implicitly has an 'any' type.
"strict": true の使い所
新規開発案件の場合は初めから true にしておくことで、安全に開発できる。
ただ、既存の JavaScript のプロジェクト等を TypeScript に移行する場合では、false にしておかないと、エラーが出まくってしまうので、
初めは false にしておいて徐々にリファクタリングを行いながら、最終的に true に持っていけたら最高のようにすると良い。
暗黙的な any の箇所はエラーにしない設定
以下のように、"noImplicitAny": false とすることで、暗黙的な any の箇所はエラーにしない設定にすることができる。
{
"include": [
"./src/**/*"
],
"compilerOptions": {
"strict": true,
"noImplicitAny": false,
"esModuleInterop": true,
"lib": [
"dom",
"es2015"
],
"jsx": "react-jsx"
}
}
すべての TSConfig のオプションのドキュメント
型定義の管理
「types」フォルダを作成し、その配下に type 毎のファイルを作成する。
export type TodoType = {
userId: number,
id: number,
title: string,
completed: boolean,
};
Pick
pick を用いると、型定義したファイルの中から必要なものを取得することが出来る。
export const Todo = (
props: Pick<TodoType, "userId" | "title" | "completed">
) => {
const { title, userId, completed = false } = props;
const completeMark = completed ? "[完]" : "[未]";
return <p>{`${completeMark} ${title}(ユーザー:${userId})`}</p>;
};
Omit
omit を用いると、型定義したファイルの中から不要なものを省略することが出来る。
export const Todo = (props: Omit<TodoType, "id">) => {
const { title, userId, completed = false } = props;
const completeMark = completed ? "[完]" : "[未]";
return <p>{`${completeMark} ${title}(ユーザー:${userId})`}</p>;
};
FC→VFC
関数の型定義に対しては、ファンクショナルコンポーネントの意味の FC を用いる。
ただ、こちらは暗黙的に children を受け取るようになっているので、VFC を用いたほうが良い場合もある。
import { VFC } from "react";
type Props = {
color: string,
fontSize: string,
};
export const Text: VFC<Props> = (props) => {
const { color, fontSize } = props;
return <p style={{ color, fontSize }}>テキストです</p>;
};
こちらは React の ver18 になれば、FC で対応が出来るようになるので VFC は暫定的な対応で用いる。
オプショナルチェイニング
接続されたオブジェクトチェーンの深くに位置するプロパティの値を、チェーン内の各参照が正しいかどうかを明示的に確認せずに読み込むことを可能とする。
export const UserProfile: VFC<Props> = (props) => {
const { user } = props;
return (
<dl>
<dt>名前</dt>
<dd>{user.name}</dd>
<dt>趣味</dt>
<dd>{user.hobbies?.join(" / ")}</dd>
</dl>
);
};
上記だと、もし hobbies が無ければ join の方に処理が行かずエラーとならない。
ライブラリの型定義
ライブラリによっては、別途インポートする必要がある。
react-router-dom は型定義が最初からされていないので、 @types/react-router-dom のインポートが必要。
ライブラリに型定義があるかどうかの確認方法
- index.d.ts がある
- package.json 内に typings という項目があって先程の index.d.ts が記述してある
比較的新しいライブラリは型定義がすでにされているものが多いので、選定する際の 1 つの目安になる。
Discussion