「TypeScript(タイプスクリプト)を学びたいけど、どこから手をつければいいかわからない…」
そんな悩みを抱えていませんか?
JavaScript(ジャバスクリプト)を書いたことがあっても、型やインターフェースなど、TypeScript特有の書き方に戸惑う人は多いです。
この記事では、TypeScriptをこれから始めたい人に向けて、基本構文をわかりやすく解説します。
よく使う書き方だけをギュッとまとめたので、これを読めばすぐにTypeScriptを書き始められます。
TypeScriptとは何か

TypeScriptの概要
TypeScriptはMicrosoft社が開発したJavaScriptを拡張したプログラミング言語です。
最大の特徴は「型(type)」を使えることで、開発中にミスを見つけやすくなり、大規模な開発でもバグが減ります。
JavaScriptとの違い
JavaScriptの問題点
// JavaScriptの例 - 実行時にエラーが起きる
function add(a, b) {
return a + b;
}
console.log(add(5, 10)); // 15 (期待通り)
console.log(add("5", "10")); // "510" (予期しない結果)
TypeScriptでの解決
// TypeScriptの例 - 開発時にエラーを検出
function add(a: number, b: number): number {
return a + b;
}
console.log(add(5, 10)); // 15 (OK)
console.log(add("5", "10")); // コンパイルエラー!
TypeScriptのメリット
開発時のエラー検出
- タイプミスの発見:プロパティ名の間違いなど
- 型の不一致:数値と文字列の混同など
- 存在しないメソッドの呼び出し:APIの変更による問題など
開発効率の向上
- エディタの支援:自動補完、リファクタリング機能
- ドキュメント化:型情報が仕様書の役割
- チーム開発:コードの意図が明確になる
開発環境の準備

Node.jsとnpmのインストール
TypeScriptを使うには、まずNode.jsが必要です。
インストール確認
node --version
npm --version
TypeScriptのインストール
グローバルインストール
npm install -g typescript
プロジェクト単位でのインストール
npm init -y
npm install --save-dev typescript
TypeScriptの実行方法
コンパイルして実行
# TypeScriptファイルをJavaScriptに変換
tsc sample.ts
# 生成されたJavaScriptファイルを実行
node sample.js
ts-nodeを使った直接実行
# ts-nodeをインストール
npm install -g ts-node
# TypeScriptファイルを直接実行
ts-node sample.ts
基本的な型の使い方

プリミティブ型
TypeScriptには以下の基本的な型があります。
数値型(number)
let age: number = 25;
let price: number = 1299.99;
let hexValue: number = 0xFF;
let binaryValue: number = 0b1010;
文字列型(string)
let userName: string = "田中太郎";
let message: string = `こんにちは、${userName}さん`;
let multiLine: string = `
これは複数行の
文字列です
`;
真偽値型(boolean)
let isComplete: boolean = true;
let isVisible: boolean = false;
let isLoggedIn: boolean = age >= 18;
null と undefined
let emptyValue: null = null;
let notDefined: undefined = undefined;
// strictNullChecksオプションで制御可能
let maybeString: string | null = null;
型推論の活用
TypeScriptは初期値から型を自動的に推論してくれます。
基本的な型推論
// 型注釈なしでも型が決まる
let autoNumber = 42; // number型
let autoString = "Hello"; // string型
let autoBool = true; // boolean型
// 型を確認(エディタで確認可能)
// autoNumber = "文字列"; // エラー:number型に文字列は代入不可
複雑な型推論
// 配列の型推論
let numbers = [1, 2, 3]; // number[]型
let mixed = [1, "hello", true]; // (string | number | boolean)[]型
// 関数の戻り値型推論
function getFullName(first: string, last: string) {
return `${first} ${last}`; // 戻り値はstring型と推論される
}
変数の宣言と型注釈

基本的な変数宣言
let と const の使い分け
// 値が変わる可能性がある場合はlet
let score: number = 0;
score = 100; // OK
// 値が変わらない場合はconst
const PI: number = 3.14159;
// PI = 3.14; // エラー:constは再代入不可
型注釈の書き方
// 基本形:変数名: 型 = 値
let userName: string = "田中太郎";
let userAge: number = 30;
let isActive: boolean = true;
// 初期値なしの場合
let futureValue: string;
futureValue = "後で設定される値";
配列の型
基本的な配列の型
// 数値の配列
let numbers: number[] = [1, 2, 3, 4, 5];
// 文字列の配列
let fruits: string[] = ["りんご", "バナナ", "オレンジ"];
// 真偽値の配列
let flags: boolean[] = [true, false, true];
Array<T>記法
// 以下は上記と同じ意味
let numbers: Array<number> = [1, 2, 3];
let fruits: Array<string> = ["りんご", "バナナ"];
混合型の配列
// ユニオン型を使った混合配列
let mixed: (string | number)[] = [1, "hello", 2, "world"];
// 別の書き方
let mixed2: Array<string | number> = [1, "hello", 2];
オブジェクトの型
インライン型注釈
let user: { name: string; age: number; email: string } = {
name: "田中太郎",
age: 30,
email: "tanaka@example.com"
};
オプショナルプロパティ
let user: {
name: string;
age: number;
email?: string; // ?をつけるとオプショナル(省略可能)
} = {
name: "佐藤花子",
age: 25
// emailは省略可能
};
読み取り専用プロパティ
let config: {
readonly apiUrl: string;
readonly timeout: number;
} = {
apiUrl: "https://api.example.com",
timeout: 5000
};
// config.apiUrl = "新しいURL"; // エラー:読み取り専用
関数の型
基本的な関数の型
通常の関数宣言
function greet(name: string): string {
return `こんにちは、${name}さん`;
}
function add(a: number, b: number): number {
return a + b;
}
function logMessage(message: string): void {
console.log(message);
// voidは戻り値がないことを示す
}
アロー関数
const greet = (name: string): string => {
return `こんにちは、${name}さん`;
};
// 短縮形
const add = (a: number, b: number): number => a + b;
// 戻り値がない場合
const logMessage = (message: string): void => {
console.log(message);
};
関数のパラメータ
デフォルトパラメータ
function greet(name: string, greeting: string = "こんにちは"): string {
return `${greeting}、${name}さん`;
}
console.log(greet("田中")); // "こんにちは、田中さん"
console.log(greet("田中", "おはよう")); // "おはよう、田中さん"
オプショナルパラメータ
function buildName(firstName: string, lastName?: string): string {
if (lastName) {
return `${firstName} ${lastName}`;
}
return firstName;
}
console.log(buildName("太郎")); // "太郎"
console.log(buildName("太郎", "田中")); // "太郎 田中"
レストパラメータ
function sum(...numbers: number[]): number {
return numbers.reduce((total, num) => total + num, 0);
}
console.log(sum(1, 2, 3)); // 6
console.log(sum(1, 2, 3, 4, 5)); // 15
関数型の変数
関数を変数に代入
// 関数型の定義
let mathOperation: (x: number, y: number) => number;
// 関数を代入
mathOperation = (a, b) => a + b;
console.log(mathOperation(5, 3)); // 8
mathOperation = (a, b) => a * b;
console.log(mathOperation(5, 3)); // 15
コールバック関数
function processArray(
items: number[],
callback: (item: number) => number
): number[] {
return items.map(callback);
}
const numbers = [1, 2, 3, 4, 5];
const doubled = processArray(numbers, x => x * 2);
console.log(doubled); // [2, 4, 6, 8, 10]
インターフェース(Interface)

基本的なインターフェース
オブジェクトの型定義
interface User {
id: number;
name: string;
email: string;
age: number;
}
let user: User = {
id: 1,
name: "田中太郎",
email: "tanaka@example.com",
age: 30
};
オプショナルプロパティ
interface Product {
id: number;
name: string;
price: number;
description?: string; // オプショナル
category?: string; // オプショナル
}
let product: Product = {
id: 1,
name: "ノートPC",
price: 98000
// descriptionとcategoryは省略可能
};
読み取り専用プロパティ
interface Config {
readonly apiUrl: string;
readonly version: string;
timeout: number; // 変更可能
}
let config: Config = {
apiUrl: "https://api.example.com",
version: "1.0.0",
timeout: 5000
};
config.timeout = 10000; // OK
// config.apiUrl = "新URL"; // エラー:読み取り専用
関数のインターフェース
関数型の定義
interface Calculator {
(x: number, y: number): number;
}
let add: Calculator = (a, b) => a + b;
let multiply: Calculator = (a, b) => a * b;
console.log(add(5, 3)); // 8
console.log(multiply(5, 3)); // 15
メソッドを持つインターフェース
interface UserService {
getUser(id: number): User;
createUser(userData: Partial<User>): User;
updateUser(id: number, userData: Partial<User>): User;
deleteUser(id: number): boolean;
}
class UserManager implements UserService {
getUser(id: number): User {
// 実装内容
return {
id: id,
name: "サンプルユーザー",
email: "user@example.com",
age: 25
};
}
createUser(userData: Partial<User>): User {
// 実装内容
return {
id: Date.now(),
name: userData.name || "無名ユーザー",
email: userData.email || "",
age: userData.age || 0
};
}
updateUser(id: number, userData: Partial<User>): User {
// 実装内容
return this.getUser(id);
}
deleteUser(id: number): boolean {
// 実装内容
return true;
}
}
インターフェースの継承
基本的な継承
interface Animal {
name: string;
age: number;
}
interface Dog extends Animal {
breed: string;
bark(): void;
}
let myDog: Dog = {
name: "ポチ",
age: 3,
breed: "柴犬",
bark() {
console.log("ワンワン!");
}
};
複数インターフェースの継承
interface Flyable {
fly(): void;
}
interface Swimmable {
swim(): void;
}
interface Duck extends Animal, Flyable, Swimmable {
quack(): void;
}
let duck: Duck = {
name: "ダック",
age: 2,
fly() {
console.log("空を飛んでいます");
},
swim() {
console.log("水を泳いでいます");
},
quack() {
console.log("クワクワ!");
}
};
ユニオン型とリテラル型

ユニオン型
基本的なユニオン型
// string または number を受け取る
let value: string | number;
value = "Hello"; // OK
value = 42; // OK
// value = true; // エラー:boolean は含まれていない
関数でのユニオン型
function formatValue(value: string | number): string {
if (typeof value === "string") {
return value.toUpperCase();
} else {
return value.toString();
}
}
console.log(formatValue("hello")); // "HELLO"
console.log(formatValue(42)); // "42"
リテラル型
文字列リテラル型
type Status = "loading" | "success" | "error";
let currentStatus: Status = "loading";
currentStatus = "success"; // OK
// currentStatus = "failed"; // エラー:定義されていない値
数値リテラル型
type DiceRoll = 1 | 2 | 3 | 4 | 5 | 6;
function rollDice(): DiceRoll {
return Math.floor(Math.random() * 6) + 1 as DiceRoll;
}
真偽値リテラル型
type Success = true;
type Failure = false;
let result: Success | Failure;
result = true; // OK
result = false; // OK
Type エイリアス
基本的なType エイリアス
複雑な型に名前をつける
type UserID = number;
type UserName = string;
type UserEmail = string;
type User = {
id: UserID;
name: UserName;
email: UserEmail;
createdAt: Date;
};
let user: User = {
id: 1,
name: "田中太郎",
email: "tanaka@example.com",
createdAt: new Date()
};
ユニオン型のエイリアス
type Theme = "light" | "dark" | "auto";
type Size = "small" | "medium" | "large";
type ButtonProps = {
text: string;
theme: Theme;
size: Size;
onClick: () => void;
};
Interface と Type の使い分け
Interfaceが適している場面
// オブジェクトの型定義
interface User {
id: number;
name: string;
}
// 継承が必要な場合
interface AdminUser extends User {
permissions: string[];
}
Typeが適している場面
// ユニオン型
type Status = "loading" | "success" | "error";
// 関数の型
type EventHandler = (event: Event) => void;
// 複雑な型の組み合わせ
type ApiResponse<T> = {
data: T;
status: Status;
message?: string;
};
実践的な例

シンプルなTodoアプリ
// 型定義
interface Todo {
id: number;
title: string;
completed: boolean;
createdAt: Date;
}
type TodoFilter = "all" | "active" | "completed";
class TodoManager {
private todos: Todo[] = [];
private nextId: number = 1;
addTodo(title: string): Todo {
const newTodo: Todo = {
id: this.nextId++,
title: title,
completed: false,
createdAt: new Date()
};
this.todos.push(newTodo);
return newTodo;
}
toggleTodo(id: number): boolean {
const todo = this.todos.find(t => t.id === id);
if (todo) {
todo.completed = !todo.completed;
return true;
}
return false;
}
getTodos(filter: TodoFilter = "all"): Todo[] {
switch (filter) {
case "active":
return this.todos.filter(t => !t.completed);
case "completed":
return this.todos.filter(t => t.completed);
default:
return this.todos;
}
}
removeTodo(id: number): boolean {
const index = this.todos.findIndex(t => t.id === id);
if (index !== -1) {
this.todos.splice(index, 1);
return true;
}
return false;
}
}
// 使用例
const todoManager = new TodoManager();
todoManager.addTodo("TypeScriptを学ぶ");
todoManager.addTodo("ブログを書く");
todoManager.toggleTodo(1);
console.log(todoManager.getTodos("active"));
ユーザー管理システム
// 型定義
interface BaseUser {
id: number;
name: string;
email: string;
}
interface RegularUser extends BaseUser {
role: "user";
lastLogin?: Date;
}
interface AdminUser extends BaseUser {
role: "admin";
permissions: string[];
}
type User = RegularUser | AdminUser;
// ユーザー管理クラス
class UserManager {
private users: User[] = [];
createRegularUser(name: string, email: string): RegularUser {
const user: RegularUser = {
id: Date.now(),
name,
email,
role: "user"
};
this.users.push(user);
return user;
}
createAdminUser(name: string, email: string, permissions: string[]): AdminUser {
const user: AdminUser = {
id: Date.now(),
name,
email,
role: "admin",
permissions
};
this.users.push(user);
return user;
}
getUser(id: number): User | undefined {
return this.users.find(user => user.id === id);
}
isAdmin(user: User): user is AdminUser {
return user.role === "admin";
}
hasPermission(user: User, permission: string): boolean {
if (this.isAdmin(user)) {
return user.permissions.includes(permission);
}
return false;
}
}
よくあるエラーと対処法

Type エラーの読み方
型の不一致エラー
// エラー例
let message: string = 123;
// Type 'number' is not assignable to type 'string'.
// 解決方法
let message: string = "123"; // 文字列にする
let messageNumber: number = 123; // 型を変更する
let messageAny: string = String(123); // 型変換する
プロパティが存在しないエラー
interface User {
name: string;
age: number;
}
let user: User = { name: "太郎", age: 30 };
// エラー例
console.log(user.email);
// Property 'email' does not exist on type 'User'.
// 解決方法1:インターフェースを拡張
interface ExtendedUser {
name: string;
age: number;
email?: string;
}
// 解決方法2:型アサーション(注意して使用)
console.log((user as any).email);
null/undefined エラー
strict モードでのエラー
// エラー例
function greet(name: string | null) {
return `Hello, ${name.toUpperCase()}`;
// Object is possibly 'null'.
}
// 解決方法1:null チェック
function greet(name: string | null) {
if (name === null) {
return "Hello, Guest";
}
return `Hello, ${name.toUpperCase()}`;
}
// 解決方法2:デフォルト値
function greet(name: string | null) {
const safeName = name || "Guest";
return `Hello, ${safeName.toUpperCase()}`;
}
開発環境の設定
tsconfig.json の基本設定
{
"compilerOptions": {
"target": "ES2020",
"module": "commonjs",
"lib": ["ES2020", "DOM"],
"outDir": "./dist",
"rootDir": "./src",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"resolveJsonModule": true
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist"]
}
エディタの設定
VS Code での設定
// .vscode/settings.json
{
"typescript.preferences.importModuleSpecifier": "relative",
"typescript.suggest.autoImports": true,
"typescript.updateImportsOnFileMove.enabled": "always",
"editor.codeActionsOnSave": {
"source.organizeImports": true
}
}
まとめ
TypeScriptの基本構文まとめ
今回紹介したTypeScriptの基本構文をまとめると:
型の基本
- プリミティブ型:
number
、string
、boolean
- 配列型:
number[]
、Array<string>
- オブジェクト型:
{ name: string; age: number }
- ユニオン型:
string | number
- リテラル型:
"success" | "error"
関数の型
- パラメータの型:
(name: string) => void
- 戻り値の型:
(): string
- オプショナルパラメータ:
(name?: string)
- デフォルトパラメータ:
(name: string = "Guest")
インターフェース
- 基本定義:
interface User { name: string }
- 継承:
interface Admin extends User
- オプショナル:
email?: string
- 読み取り専用:
readonly id: number
Type エイリアス
- 型の別名:
type UserID = number
- ユニオン型:
type Status = "loading" | "success"
- 複雑な型:
type ApiResponse<T> = { data: T }
コメント