TypeScriptの型定義の概要

TypeScript の一般的な型定義パターンをクイックリファレンスとしてまとめます。

組み込みプリミティブ型

  • string: テキストデータ。例: hello
  • number: 整数と浮動小数点数を含むすべての数値。例: 1003.14
  • bigint: 任意の大きさの整数。例: 12345678901234567890n
  • boolean: 真偽値。例: truefalse
  • symbol: 一意かつ不変の値。例: Symbol('key')
  • undefined: 宣言されているが値が割り当てられていない変数。例: undefined
  • null: 意図的に値がない状態。例: null
  • void: 値を返さない関数の戻り値の型として使用されます。例: function log(): void { console.log('Hello'); }
  • never: 決して発生しない値。例: function fail(message: string): never { throw new Error(message); }
  • unknown: 任意の値を表しますが、any よりも安全です。使用前に型チェックを行う必要があります。例: let value: unknown = 1;
  • any: 型チェックを無効にします。例: let a: any = 'hello'; a = 1;

オブジェクトタイプ

  • Plain Object (object)
let person: object = { name: 'Alice', age: 30 };
  • Specific Object Shapes (via {})
let user: { name: string; age: number } = { name: 'Bob', age: 25 };
  • Interfaces
interface User {
  name: string;
  age: number;
}
let u: User = { name: 'Carol', age: 22 };
  • Enums
enum Color {
  Red,
  Green,
  Blue,
}
  • Type Aliases
type Point = { x: number; y: number };
  • Arrays (Array<T> or T[])
let scores: number[] = [90, 85, 100];
let names: Array<string> = ['Alice', 'Bob'];
  • Tuples
let point: [number, number] = [10, 20];
let userInfo: [string, number] = ['Alice', 30];
  • Classes
class Animal {
  name: string;
  constructor(name: string) {
    this.name = name;
  }
}
const dog = new Animal('Doggo');
  • Functions (Function type)
let greet: (name: string) => string = (name) => `Hello, ${name}!`;
  • Callable Objects
interface Callable {
  (x: number): number;
  description: string;
}
const square: Callable = Object.assign((x: number) => x * x, { description: 'Squares a number' });
  • Constructors (new)
interface Constructor {
  new (s: string): object;
}
  • Index Signatures
interface StringMap {
  [key: string]: string;
}
let dict: StringMap = { key1: 'value1', key2: 'value2' };
  • Indexed Access Types
// Accessing Object Properties
interface Person {
  name: string;
  age: number;
}
type PersonName = Person['name'];  // `PersonName` is `string`
type PersonAge = Person['age'];    // `PersonAge` is `number`

// Accessing Array Elements
type Numbers = number[];
type FirstNumber = Numbers[0];  // `FirstNumber` is `number`

// Using With String Literal Types
type Colors = 'red' | 'green' | 'blue';
type ColorLength = Colors['length'];  // `ColorLength` is `number`

// Accessing Nested Object Properties
interface Car {
  brand: string;
  specs: {
    engine: string;
    wheels: number;
  };
}
type EngineType = Car['specs']['engine'];  // `EngineType` is `string`
type WheelCount = Car['specs']['wheels']; // `WheelCount` is `number`

// Conditional Types with Indexed Access
type PropertyType<T, K extends keyof T> = T[K];
interface Car {
  brand: string;
  year: number;
}
type CarBrand = PropertyType<Car, 'brand'>;  // `CarBrand` is `string`
type CarYear = PropertyType<Car, 'year'>;    // `CarYear` is `number`
  • Mapped Types
type ReadOnly<T> = {
  readonly [K in keyof T]: T[K];
};
  • Template Literal Types
type Greeting = `Hello ${string}`;
let greeting: Greeting = 'Hello world'; // Works fine
greeting = 'Hello John';                // Works fine
greeting = 'Hi John';                   // Error: Type 'Hi John' is not assignable to type 'Greeting'
  • Utility Types
Partial<T>
Required<T>
Readonly<T>
Pick<T, K>
Omit<T, K>
Record<K, T>
Exclude<T, U>
Extract<T, U>
NonNullable<T>
ReturnType<T>
Parameters<T>
Awaited<T>
// ...
  • Intersection Types
type Worker = User & { jobTitle: string };
  • Union Types
type Shape = Circle | Rectangle;

interface Circle {
  radius: number;
}

interface Rectangle {
  width: number;
  height: number;
}
  • Structural Typing (Duck Typing)
let obj: {name: string} = {name: 'Alice', age: 30}; // allowed!
  • Literal Object Types
type Status = {
  state: 'loading' | 'success' | 'error';
};
  • Special Types

    • object: 非プリミティブ型のみ(null または undefined は不可)。
    • {}: ほぼすべての null/undefined 以外の値(42 でも {} です!)
    • Object: JavaScript の Object 型:ほぼすべての値(関数や配列も含む)。
  • Special: Record<string, unknown> pattern

type LooseObject = Record<string, unknown>;

// equivalent to

type LooseObject = {
  [key: string]: unknown;
};

インターフェースの詳細

  • Basic Interface
interface User {
  name: string;
  age: number;
}

const user: User = { name: 'Alice', age: 30 };
  • Optional Properties
interface User {
  name: string;
  age?: number;  // optional
}

const user1: User = { name: 'Alice' };
const user2: User = { name: 'Bob', age: 25 };
  • Readonly Properties
interface User {
  readonly name: string;
  age: number;
}

const user: User = { name: 'Alice', age: 30 };
user.name = 'Bob';  // Error: Cannot assign to 'name' because it is a read-only property.
  • Function Types in Interfaces
interface Greet {
  (name: string): string;
}

const greet: Greet = (name) => `Hello, ${name}`;
  • Extending Interfaces
interface Person {
  name: string;
}

interface Employee extends Person {
  employeeId: number;
}

const employee: Employee = { name: 'Alice', employeeId: 123 };
  • Interface with Index Signatures
interface Dictionary {
  [key: string]: string;
}

const myDict: Dictionary = {
  apple: 'A fruit',
  car: 'A vehicle'
};
  • Intersection with Other Types
interface Product {
  name: string;
  price: number;
}

type DiscountedProduct = Product & {
  discount: number;
};

const discounted: DiscountedProduct = { name: 'Shoes', price: 50, discount: 10 };
  • Interfaces with Classes
interface Movable {
  move(): void;
}

class Car implements Movable {
  move() {
    console.log('The car is moving!');
  }
}
  • Interface with Method Signatures
interface Calculator {
  add(a: number, b: number): number;
  subtract(a: number, b: number): number;
}

const myCalculator: Calculator = {
  add: (a, b) => a + b,
  subtract: (a, b) => a - b
};
  • Interfaces with Optional Method Signatures
interface Logger {
  log?: (message: string) => void;
}

const logger: Logger = {
  log: (message) => console.log(message)
};

const silentLogger: Logger = {};  // This is valid because `log` is optional
  • Interfaces with extends and Multiple Inheritance
interface Worker {
  work(): void;
}

interface Manager {
  manage(): void;
}

interface Supervisor extends Worker, Manager {}

const supervisor: Supervisor = {
  work() {
    console.log('Working');
  },
  manage() {
    console.log('Managing');
  }
};
  • Merging Interfaces
interface Person {
  name: string;
}

interface Person {
  age: number;
}

const person: Person = { name: 'Alice', age: 30 };
  • Interface with Type Parameters (Generics)
interface Box<T> {
  value: T;
}

const stringBox: Box<string> = { value: 'Hello' };
const numberBox: Box<number> = { value: 42 };
  • Hybrid Types
interface Counter {
  (start: number): string;   // Function signature
  value: number;             // Property
}

const counter: Counter = (start: number) => `Count: ${start}`;
counter.value = 0;

型の詳細

  • Basic Type Aliases
type Name = string;

const userName: Name = 'Alice';  // Equivalent to 'string' but using the alias.
  • Union Types
type Status = 'loading' | 'success' | 'error';

const currentStatus: Status = 'loading';  // Valid
  • Intersection Types
type Person = {
  name: string;
  age: number;
};

type Employee = Person & {
  employeeId: number;
};

const employee: Employee = { name: 'Alice', age: 30, employeeId: 123 };
  • Literal Types
type Color = 'red' | 'green' | 'blue';

const color: Color = 'green';  // Valid
  • Tuple Types
type Point = [number, number];

const point: Point = [10, 20];  // Valid
  • Function Types
type Greet = (name: string) => string;

const greet: Greet = (name) => `Hello, ${name}`;
  • Optional Properties
type User = {
  name: string;
  age?: number;  // Optional property
};

const user1: User = { name: 'Alice' };
const user2: User = { name: 'Bob', age: 30 };
  • Readonly Properties
type User = {
  readonly name: string;
  age: number;
};

const user: User = { name: 'Alice', age: 30 };
user.name = 'Bob';  // Error: Cannot assign to 'name' because it is a read-only property.
  • Mapped Types
type Person = { name: string; age: number };

type ReadOnlyPerson = { readonly [K in keyof Person]: Person[K] };

const person: ReadOnlyPerson = { name: 'Alice', age: 30 };
person.name = 'Bob';  // Error: Cannot assign to 'name' because it is a read-only property.
  • Conditional Types
type IsString<T> = T extends string ? 'Yes' : 'No';

type A = IsString<string>;  // 'Yes'
type B = IsString<number>;  // 'No'
  • Type Inference
type User = { name: string; age: number };

const user = { name: 'Alice', age: 30 };  // TypeScript infers `User` type automatically
  • Type Aliases with Generics
type Box<T> = { value: T };

const stringBox: Box<string> = { value: 'Hello' };
const numberBox: Box<number> = { value: 42 };
  • Union of Object Types
type Success = { status: 'success'; data: string };
type Error = { status: 'error'; message: string };

type Response = Success | Error;

const response: Response = { status: 'success', data: 'Hello, world!' };
  • Intersection of Object Types
type Person = { name: string };
type Employee = { employeeId: number };

type Worker = Person & Employee;

const worker: Worker = { name: 'Alice', employeeId: 123 };
  • Type Guards and Type Aliases
type User = { name: string; age: number };
type Admin = { name: string; role: string };

function isUser(user: User | Admin): user is User {
  return (user as User).age !== undefined;
}

const person: User | Admin = { name: "Alice", age: 30 };
if (isUser(person)) {
  console.log(person.age);  // Safe, because it's narrowed to 'User'
}
  • Utility Types Using type
type User = { name: string; age: number };

// Partial<User> makes all properties optional
type PartialUser = Partial<User>;

// Pick<User, 'name'> picks specific properties
type UserName = Pick<User, 'name'>;

interfacetype のどちらかを選択します

  • オブジェクトの形状やクラスを定義する場合、および拡張性が必要な場合(インターフェースをマージしたり拡張したりする場合など)には、interface を使用します。
  • ユニオン、インターセクション、ジェネリックなどのより複雑な型や、配列、タプル、関数などの非オブジェクト型のエイリアス、またはより高度なシナリオには、type を使用します。

keyoftypeof の比較

  • keyof: returns a union of property names (keys) of an object type
type Person = {
  name: string;
  age: number;
};

type PersonKeys = keyof Person;  // "name" | "age"
  • typeof: returns the type of a value (like string, number, or any object type)
const userName = 'Alice';
type UserNameType = typeof userName;  // string

function greet(user: string) {
  return `Hello, ${user}`;
}
type GreetFunctionType = typeof greet;  // (user: string) => string
  • keyof and typeof used together
const person = {
  name: 'Alice',
  age: 30,
};

type PersonKeys = keyof typeof person;  // "name" | "age"

空間と空間の両方に存在するもの

  • Variables and Constants
const userName = 'Alice';  // `userName` is a **value** in value space and has the value `"Alice"`
type UserNameType = typeof userName;  // `typeof userName` is a **type** in type space (`string`)

const userAge = 30;  // `userAge` is a **value** in value space
type UserAgeType = typeof userAge;  // `typeof userAge` is a **type** in type space (`number`)
  • Functions
function greet(name: string): string {
  return `Hello, ${name}!`;
}

const greetType: typeof greet = greet;  // `greet` is a **value** in value space and has the function implementation.
type GreetType = typeof greet;  // `typeof greet` is a **type** in type space that describes the function's signature
  • Classes
class Person {
  constructor(public name: string, public age: number) {}
}

const person1 = new Person('Alice', 30);  // `person1` is a **value** in value space (an instance of `Person`)

type PersonType = typeof Person;  // `typeof Person` is a **type** in type space, representing the class constructor
type PersonInstanceType = Person;  // `Person` is also a **type** in type space, representing the type of instances created by the class
  • Enums
enum Status {
  Loading = 'loading',
  Success = 'success',
  Error = 'error'
}

const currentStatus = Status.Loading;  // `currentStatus` is a **value** in value space (the string "loading")

type StatusType = typeof Status;  // `typeof Status` is a **type** in type space (the enum itself)
type StatusValues = Status;  // `Status` is a **type** in type space, representing the enum values
  • Type Assertions
const someValue: any = 'Hello!';
const stringValue = someValue as string;  // `stringValue` is a **value** in value space, and we assert that it has a **type** `string` in type space

消去不可能なタイプ

  • typeof Operator
const str = 'Hello';
type StrType = typeof str;  // 'string' is the type inferred.

// In runtime, `typeof str` will be a reference to the actual value (string "Hello").
  • Enums
enum Color {
  Red,
  Green,
  Blue
}

const colorValue = Color.Red;  // Color is a non-erasable value, it gets converted into an object.

after compilation:

var Color;
(function (Color) {
    Color[Color['Red'] = 0] = 'Red';
    Color[Color['Green'] = 1] = 'Green';
    Color[Color['Blue'] = 2] = 'Blue';
})(Color || (Color = {}));
  • const Assertions
const fruit = 'apple' as const;  // "apple" is a literal type, this type is non-erasable.

type FruitType = typeof fruit;  // "apple" is a non-erasable type because it will be part of the generated JS.
  • Classes and Class Instances
class Person {
  constructor(public name: string, public age: number) {}
}

const person1 = new Person('Alice', 30);
  • Interfaces (used for code generation)

    インターフェースは、生成された JavaScript では実行時に消去されますが、コード生成に使用される場合は、コンパイル時に型チェックが実施され、生成されるコードの構造に影響を与えるため、消去不可能な型になります。

interface IShape {
  x: number;
  y: number;
}

型アサーション

  • Angle Bracket (<Type>) Syntax (old syntax)
let value: unknown = 'hello';
let strLength: number = (<string>value).length;
  • as Syntax (recommended, more modern syntax)
let value: unknown = 'hello';
let strLength: number = (value as string).length;
  • Non-null Assertion (!)
let someValue: string | null = 'Hello';

// TypeScript will give an error because `someValue` could be `null`.
let length = someValue.length;  // Error: Object is possibly 'null'.

// Using non-null assertion to tell TypeScript we're sure it's not null.
let length = someValue!.length;  // Works fine, assuming `someValue` is never null.
  • Definite Assignment Assertion (!)
class MyClass {
  name!: string;  // Use `!` to tell TypeScript this will be assigned before use.

  constructor() {
    // Initialization later
    this.name = 'John Doe';
  }

  printName() {
    console.log(this.name);  // Works fine, name is assigned before use.
  }
}

const myClassInstance = new MyClass();
myClassInstance.printName();  // Output: John Doe
  • Const Assertion
let point = { x: 10, y: 20 } as const;
  • Double Assertion
let someNumber: number = '123' as unknown as number;

型述語

function isString(value: any): value is string {
  return typeof value === 'string';
}

型アサーションと型述語の比較

  • 型アサーション:「TypeScriptよりも詳しいので、正しい型だと仮定するだけです。」
  • 型述語:「きちんと検証すれば、TypeScriptは結果を信頼してくれます。」
// type assertion
let data: any = 'hello';
let length: number = (data as string).length; // Tell TS: treat 'data' as string

// type predicate
function isString(value: any): value is string {
  return typeof value === 'string';
}
function example(value: any) {
  if (isString(value)) {
    console.log(value.toUpperCase()); // TS knows it's string safely here
  }
}

typescript