第1章で学んだ基本的な型を使って、より実践的な型定義の方法を学びましょう。
Type Alias - 型に名前をつける
Type Aliasを使うと、複雑な型に名前をつけて再利用できます。
基本的な使い方
// 長い型を何度も書くのは大変...
const user1: { id: number; name: string; email: string } = {
id: 1,
name: "太郎",
email: "[email protected]"
};
const user2: { id: number; name: string; email: string } = {
id: 2,
name: "花子",
email: "[email protected]"
};
// Type Aliasで名前をつける
type User = {
id: number;
name: string;
email: string;
};
// シンプルに書ける!
const user1: User = {
id: 1,
name: "太郎",
email: "[email protected]"
};
const user2: User = {
id: 2,
name: "花子",
email: "[email protected]"
};ポイント:
typeキーワードを使う- 型に好きな名前をつけられる
- 同じ型を何度も使う場合に便利
React開発での実践例
// ユーザー情報の型
type User = {
id: number;
name: string;
email: string;
avatar?: string; // オプショナル
};
// Propsの型
type UserCardProps = {
user: User;
onClick: () => void;
};
function UserCard({ user, onClick }: UserCardProps) {
return (
<div onClick={onClick}>
<h2>{user.name}</h2>
<p>{user.email}</p>
</div>
);
}
// 使用例
const userData: User = {
id: 1,
name: "太郎",
email: "[email protected]"
};
<UserCard user={userData} onClick={() => console.log("クリック")} />Union型とLiteral型 - より柔軟な型定義
Union型 - 複数の型を許容する
Union型を使うと、「AまたはB」という型を定義できます。
// IDは文字列でも数値でもOK
type ID = string | number;
let userId: ID;
userId = "abc123"; // OK
userId = 12345; // OK
// userId = true; // エラー!booleanは許可されていない|(パイプ)で型を区切ります。
React開発での実践例
// データ読み込み中はnull、読み込み後はデータ
type UserData = User | null;
const [userData, setUserData] = useState<UserData>(null);
if (userData === null) {
return <p>読み込み中...</p>;
}
return <p>こんにちは、{userData.name}さん!</p>;Literal型 - 特定の値だけを許可する
Literal型を使うと、特定の値だけを許可する型を定義できます。
// この3つの文字列しか入らない
type Status = "success" | "error" | "loading";
let status: Status;
status = "success"; // OK
status = "error"; // OK
status = "loading"; // OK
// status = "pending"; // エラー!この値は許可されていないReact開発での実践例
// ボタンのバリアント(見た目のパターン)
type ButtonVariant = "primary" | "secondary" | "danger";
type ButtonProps = {
variant: ButtonVariant;
children: React.ReactNode;
};
function Button({ variant, children }: ButtonProps) {
const colors = {
primary: "bg-blue-500",
secondary: "bg-gray-500",
danger: "bg-red-500"
};
return (
<button className={colors[variant]}>
{children}
</button>
);
}
// 使用例
<Button variant="primary">保存</Button>
<Button variant="danger">削除</Button>
// <Button variant="warning">警告</Button> // エラー!Literal型のメリット:
- ✅ タイプミスを防げる
- ✅ エディタの自動補完が効く
- ✅ どんな値が使えるか一目でわかる
void型 - 戻り値がない関数
void型は、関数が値を返さない時に使います。
基本的な使い方
// 戻り値がない関数
function logMessage(message: string): void {
console.log(message);
// returnしない
}
// アロー関数でも同じ
const showAlert = (message: string): void => {
alert(message);
};React開発での実践例
イベントハンドラはvoid型を返します。
// Propsでイベントハンドラを受け取る
type ButtonProps = {
onClick: () => void; // voidを返す関数
children: React.ReactNode;
};
function Button({ onClick, children }: ButtonProps) {
return <button onClick={onClick}>{children}</button>;
}
// 使用例
function App() {
const handleClick = (): void => {
console.log("ボタンがクリックされました");
};
return <Button onClick={handleClick}>クリック</Button>;
}よく見るパターン
function Counter() {
const [count, setCount] = useState(0);
// イベントハンドラはvoid型を返す
const handleClick = (): void => {
setCount(count + 1);
};
const handleSubmit = (e: React.FormEvent): void => {
e.preventDefault();
// フォーム送信処理
};
return (
<div>
<p>カウント: {count}</p>
<button onClick={handleClick}>+1</button>
</div>
);
}タプル型 - 固定長の配列
タプル型は、要素数と各要素の型が決まっている配列です。
基本的な使い方
// 普通の配列 - 何個でも入る、全て同じ型
const numbers: number[] = [1, 2, 3, 4, 5];
// タプル - 2つだけ、1つ目はstring、2つ目はnumber
const person: [string, number] = ["太郎", 25];
// 分割代入で取り出せる
const [name, age] = person;
console.log(name); // "太郎" (string型)
console.log(age); // 25 (number型)
// エラー!要素数が違う
// const person: [string, number] = ["太郎", 25, "追加"];
// エラー!型が違う
// const person: [string, number] = [25, "太郎"];タプルの特徴:
- 要素数が固定
- 各位置の型が決まっている
- 順序が重要
React開発での実践例 - useState
実は、useStateの戻り値がタプルです!
より深く理解するために: 第4章「React Hooks - useState」でタプル型の実践的な使い方を学んだ後、このセクションを読み返すとより理解が深まります。
const [count, setCount] = useState(0);useStateの型定義を見てみると:
// useStateの型定義(簡略版)
function useState<T>(initialValue: T): [T, (value: T) => void]
// ↑
// タプル型!
// つまり
const result = useState(0);
// result の型: [number, (value: number) => void]
// 分割代入で取り出す
const [count, setCount] = result;
// count: number
// setCount: (value: number) => voidなぜタプルを使うのか?
// もしオブジェクトだったら...
const { value, setValue } = useState(0); // 名前が固定されてしまう
// タプルなら...
const [count, setCount] = useState(0); // 好きな名前をつけられる
const [name, setName] = useState(""); // 何度も使える
const [isOpen, setIsOpen] = useState(false);複数の値を返す関数
// 座標を返す関数
function getMousePosition(): [number, number] {
// マウスの位置を取得(例)
return [100, 200]; // [x座標, y座標]
}
const [x, y] = getMousePosition();
console.log(`x: ${x}, y: ${y}`); // "x: 100, y: 200"
// カスタムフック
function useFormField(initialValue: string): [string, (e: React.ChangeEvent<HTMLInputElement>) => void] {
const [value, setValue] = useState(initialValue);
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
setValue(e.target.value);
};
return [value, handleChange]; // タプルで返す
}
// 使用例
function LoginForm() {
const [email, handleEmailChange] = useFormField("");
const [password, handlePasswordChange] = useFormField("");
return (
<form>
<input value={email} onChange={handleEmailChange} />
<input value={password} onChange={handlePasswordChange} type="password" />
</form>
);
}インターフェース (Interface)
インターフェースは、オブジェクトの「形」を定義する機能です。Type Aliasと似ていますが、いくつか違いがあります。
基本的な使い方
// インターフェースの定義
interface User {
name: string;
age: number;
email: string;
}
// インターフェースを使う
const user1: User = {
name: "太郎",
age: 25,
email: "[email protected]"
};
const user2: User = {
name: "花子",
age: 23,
email: "[email protected]"
};オプショナルプロパティ
必須ではないプロパティには ? をつけます。
interface User {
name: string;
age: number;
email: string;
phone?: string; // phoneは省略可能
avatar?: string; // avatarも省略可能
}
// phoneがなくてもOK
const user1: User = {
name: "太郎",
age: 25,
email: "[email protected]"
};
// phoneがあってもOK
const user2: User = {
name: "花子",
age: 23,
email: "[email protected]",
phone: "090-1234-5678"
};readonlyプロパティ
変更を禁止したいプロパティには readonly をつけます。
interface User {
readonly id: number; // IDは変更できない
name: string;
email: string;
}
const user: User = {
id: 1,
name: "太郎",
email: "[email protected]"
};
user.name = "次郎"; // OK
// user.id = 2; // エラー!idは変更できないインターフェースの拡張 (extends)
既存のインターフェースを拡張して、新しいプロパティを追加できます。
// 基本のUser
interface User {
name: string;
email: string;
}
// Userを拡張してAdminを作る
interface Admin extends User {
role: string;
permissions: string[];
}
const admin: Admin = {
name: "管理者",
email: "[email protected]",
role: "super_admin",
permissions: ["read", "write", "delete"]
};interfaceとtype aliasの違い
// interface: オブジェクトの形を定義するのに適している
interface User {
name: string;
age: number;
}
// type: Union型やLiteral型も定義できる
type ID = string | number;
type Status = "success" | "error" | "loading";
// type: オブジェクトも定義できる
type User = {
name: string;
age: number;
};使い分けのコツ:
- オブジェクトの形を定義する場合 →
interfaceを使うことが多い - Union型やLiteral型を定義する場合 →
typeを使う - React開発では、Propsの型定義に
interfaceがよく使われる
React開発での実践例
// Propsの型をinterfaceで定義
interface UserCardProps {
user: {
name: string;
age: number;
email: string;
};
onEdit?: () => void; // オプショナル
}
function UserCard({ user, onEdit }: UserCardProps) {
return (
<div>
<h2>{user.name}</h2>
<p>年齢: {user.age}歳</p>
<p>メール: {user.email}</p>
{onEdit && <button onClick={onEdit}>編集</button>}
</div>
);
}
// さらに改善:Userの型も分離
interface User {
name: string;
age: number;
email: string;
}
interface UserCardProps {
user: User;
onEdit?: () => void;
}
function UserCard({ user, onEdit }: UserCardProps) {
return (
<div>
<h2>{user.name}</h2>
<p>年齢: {user.age}歳</p>
<p>メール: {user.email}</p>
{onEdit && <button onClick={onEdit}>編集</button>}
</div>
);
}ジェネリクス - ライブラリの型を読むための基礎知識
ジェネリクスは、「型をパラメータとして受け取る」機能です。自分で書くことは少ないですが、ReactやTypeScriptのライブラリを使う時に頻繁に見かけます。
ジェネリクスとは?
<T> のような書き方を見たことがありませんか?これがジェネリクスです。
// よく見るパターン
const [count, setCount] = useState<number>(0);
const [name, setName] = useState<string>("");
const [users, setUsers] = useState<User[]>([]);
// 配列の型
const numbers: Array<number> = [1, 2, 3];
const names: Array<string> = ["太郎", "花子"];<number> や <string> の部分が「型パラメータ」です。
なぜジェネリクスが必要?
例えば、useStateは数値でも文字列でもオブジェクトでも使えます。これはジェネリクスのおかげです。
// useStateの型定義(簡略版)
function useState<T>(initialValue: T): [T, (value: T) => void]
// ↑型パラメータ
// 使用例
const [count, setCount] = useState<number>(0);
// Tがnumberになる → [number, (value: number) => void]
const [name, setName] = useState<string>("");
// Tがstringになる → [string, (value: string) => void]よく見るパターン
// useState - 型を明示する
const [user, setUser] = useState<User | null>(null);
// useState - 型推論に任せる(これでもOK)
const [count, setCount] = useState(0); // number型と推論される
// 配列
const numbers: Array<number> = [1, 2, 3];
// これと同じ意味
const numbers: number[] = [1, 2, 3];
// Promiseの型
const fetchUser = async (): Promise<User> => {
const response = await fetch("/api/user");
return response.json();
};基本的な書き方(参考)
自分で書くことは少ないですが、簡単な例を見てみましょう。
// 配列の最初の要素を返す関数
function first<T>(arr: T[]): T {
return arr[0];
}
// どんな型でも使える!
const num = first([1, 2, 3]); // numはnumber型
const str = first(["a", "b", "c"]); // strはstring型実際の開発では:
- ジェネリクスを自分で書くことは少ない
- useStateやPromiseなど、既存のものを使う時に見かける
- 「
<>の中に型を書く」と覚えておけばOK
型アサーション - 型を明示的に指定する
型アサーションは、「この値は○○型だよ」とTypeScriptに教える機能です。
基本的な使い方
const value: any = "hello";
const length: number = (value as string).length;
// 別の書き方(古い書き方、あまり使わない)
const length: number = (<string>value).length;as 型名 で型を指定します。
React開発での実践例
例1: DOM要素の取得
const button = document.getElementById("myButton") as HTMLButtonElement;
button.disabled = true;
const input = document.querySelector("input") as HTMLInputElement;
console.log(input.value);例2: イベントハンドラ
function handleChange(e: Event) {
const target = e.target as HTMLInputElement;
console.log(target.value);
}
// React��イベントハンドラ
function handleSubmit(e: React.FormEvent) {
const form = e.target as HTMLFormElement;
const formData = new FormData(form);
}⚠️ 注意点
型アサーションは「あなたがTypeScriptより詳しい」と宣言することです。間違った型を指定すると実行時エラーになります。
// 危険な例
const value: any = 123;
const text = value as string;
console.log(text.toUpperCase()); // 実行時エラー!
// 本当に確信がある時だけ使う
const button = document.getElementById("myButton");
if (button) {
// buttonが存在することを確認してから使う
const htmlButton = button as HTMLButtonElement;
htmlButton.disabled = true;
}使い方のコツ:
- 本当に型が分かっている時だけ使う
- DOM要素の取得など、限定的な場面で使う
- 多用しない(型推論やUnion型で解決できないか考える)
まとめ
この章では、実践的な型定義の方法を学びました。
型定義の基本
- Type Alias: 型に名前をつけて再利用する
- Union型: 複数の型を許容する(
A | B) - Literal型: 特定の値だけを許可する
実践的な型
- void型: 戻り値がない関数(イベントハンドラでよく使う)
- タプル型: 固定長の配列(useStateの戻り値など)
オブジェクトの型定義
- interface: オブジェクトの形を定義、拡張可能
- オプショナルプロパティ(
?)、readonly - interfaceとtype aliasの使い分け
応用
- ジェネリクス:
<T>のように使う(主に既存のライブラリで見かける) - 型アサーション:
as 型名で型を指定(慎重に使う)
💡 次のステップ
これでTypeScriptの基礎は完璧です!次はReactの基礎を学んで、実際にコンポーネントを作っていきましょう。