TypeScriptの型定義の概要
TypeScript の一般的な型定義パターンをクイックリファレンスとしてまとめます。
組み込みプリミティブ型
string
: テキストデータ。例:hello
number
: 整数と浮動小数点数を含むすべての数値。例:100
、3.14
bigint
: 任意の大きさの整数。例:12345678901234567890n
boolean
: 真偽値。例:true
、false
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>
orT[]
)
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'>;
interface
と type
のどちらかを選択します
- オブジェクトの形状やクラスを定義する場合、および拡張性が必要な場合(インターフェースをマージしたり拡張したりする場合など)には、
interface
を使用します。 - ユニオン、インターセクション、ジェネリックなどのより複雑な型や、配列、タプル、関数などの非オブジェクト型のエイリアス、またはより高度なシナリオには、
type
を使用します。
keyof
と typeof
の比較
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 (likestring
,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
andtypeof
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
}
}