[2026] TypeScript Interfaces | Complete Guide
이 글의 핵심
Interfaces in TypeScript: optional and readonly props, call signatures, index signatures, extends, declaration merging, implements, and when to prefer interface vs type alias.
Introduction
An interface describes the shape of objects in TypeScript.
1. Interface basics
Declaration
An interface lists the properties an object must have and their types: 다음은 typescript를 활용한 상세한 구현 코드입니다. 클래스를 정의하여 데이터와 기능을 캡슐화하며. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
// User interface — defines the object "contract"
interface User {
id: string;
name: string;
age: number;
email: string;
}
// ✅ Valid: all required properties provided
const user: User = {
id: "U001",
name: "Alice",
age: 25,
email: "alice@test.com"
};
// ❌ Missing properties
// const user2: User = { id: "U002", name: "Bob" };
// ❌ Wrong types
// const user3: User = { ..., age: "25", ....};
// ❌ Unknown extra properties (in object literals with explicit type)
// const user4: User = { ..., phone: "..." };
What interfaces give you:
- Type checking: validate object structure at compile time
- Autocomplete: IDE suggests property names
- Documentation: the shape is explicit
- Refactoring: rename or change types with confidence
Optional properties
Use ? for optional properties:
다음은 typescript를 활용한 상세한 구현 코드입니다. 클래스를 정의하여 데이터와 기능을 캡슐화하며, 함수를 통해 로직을 구현합니다, 조건문으로 분기 처리를 수행합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
interface User {
id: string;
name: string;
age?: number;
email?: string;
}
// ✅ OK without optional fields
const user1: User = {
id: "U001",
name: "Alice"
};
// ✅ OK with optional fields
const user2: User = {
id: "U002",
name: "Bob",
age: 30,
email: "bob@test.com"
};
function printAge(user: User) {
if (user.age !== undefined) {
console.log(user.age.toFixed(0));
}
console.log(user.age?.toFixed(0));
const age = user.age ?? 0;
console.log(age);
}
printAge(user1);
printAge(user2);
Why optional properties help:
- Flexible shapes
- Partial updates
- APIs where some fields may be absent
Readonly properties
readonly marks properties that must not be reassigned after initialization:
다음은 typescript를 활용한 상세한 구현 코드입니다. 클래스를 정의하여 데이터와 기능을 캡슐화하며, 에러 처리를 통해 안정성을 확보합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
// 타입 정의
interface User {
readonly id: string;
name: string;
age: number;
}
const user: User = {
id: "U001",
name: "Alice",
age: 25
};
user.name = "Bob"; // ✅
user.age = 30; // ✅
// user.id = "U002"; // ❌ error
interface Post {
readonly id: string;
readonly createdAt: Date;
title: string;
content: string;
updatedAt: Date;
}
const post: Post = {
id: "POST001",
createdAt: new Date(),
title: "First post",
content: "Body",
updatedAt: new Date()
};
post.title = "Updated title";
post.content = "Updated body";
post.updatedAt = new Date();
readonly vs const:
readonly: property on an objectconst: binding for a variable
const user: User = { id: "U001", name: "Alice", age: 25 };
// user cannot be reassigned
// user.id cannot be reassigned
2. Function types in interfaces
Methods
다음은 typescript를 활용한 상세한 구현 코드입니다. 클래스를 정의하여 데이터와 기능을 캡슐화하며. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
interface Calculator {
add(a: number, b: number): number;
subtract(a: number, b: number): number;
multiply?(a: number, b: number): number;
}
const calc: Calculator = {
add(a, b) {
return a + b;
},
subtract(a, b) {
return a - b;
}
};
console.log(calc.add(10, 5));
console.log(calc.subtract(10, 5));
Call signatures
아래 코드는 typescript를 사용한 구현 예제입니다. 클래스를 정의하여 데이터와 기능을 캡슐화하며. 코드를 직접 실행해보면서 동작을 확인해보세요.
interface MathOperation {
(a: number, b: number): number;
}
const add: MathOperation = (a, b) => a + b;
const multiply: MathOperation = (a, b) => a * b;
console.log(add(10, 5));
console.log(multiply(10, 5));
Constructor types
다음은 typescript를 활용한 상세한 구현 코드입니다. 클래스를 정의하여 데이터와 기능을 캡슐화하며, 함수를 통해 로직을 구현합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
interface ClockConstructor {
new (hour: number, minute: number): ClockInterface;
}
interface ClockInterface {
tick(): void;
}
class DigitalClock implements ClockInterface {
constructor(h: number, m: number) {}
tick() {
console.log("beep beep");
}
}
function createClock(
ctor: ClockConstructor,
hour: number,
minute: number
): ClockInterface {
return new ctor(hour, minute);
}
const clock = createClock(DigitalClock, 12, 17);
clock.tick();
3. Index signatures
String index
아래 코드는 typescript를 사용한 구현 예제입니다. 클래스를 정의하여 데이터와 기능을 캡슐화하며. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
interface StringMap {
[key: string]: string;
}
const colors: StringMap = {
red: "#FF0000",
green: "#00FF00",
blue: "#0000FF"
};
console.log(colors[red]);
console.log(colors.green);
Numeric index
아래 코드는 typescript를 사용한 구현 예제입니다. 클래스를 정의하여 데이터와 기능을 캡슐화하며. 코드를 직접 실행해보면서 동작을 확인해보세요.
interface NumberArray {
[index: number]: string;
}
const fruits: NumberArray = ["apple", "banana", "orange"];
console.log(fruits[0]);
console.log(fruits[1]);
Mixed constraints
아래 코드는 typescript를 사용한 구현 예제입니다. 클래스를 정의하여 데이터와 기능을 캡슐화하며. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
interface Dictionary {
[key: string]: string | number;
length: number;
}
const dict: Dictionary = {
name: "Alice",
age: 25,
length: 2
};
4. Extending interfaces
extends
다음은 typescript를 활용한 상세한 구현 코드입니다. 클래스를 정의하여 데이터와 기능을 캡슐화하며. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
interface Person {
name: string;
age: number;
}
interface Employee extends Person {
employeeId: string;
department: string;
}
const employee: Employee = {
name: "Alice",
age: 30,
employeeId: "E001",
department: "Engineering"
};
Multiple inheritance
다음은 typescript를 활용한 상세한 구현 코드입니다. 클래스를 정의하여 데이터와 기능을 캡슐화하며. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
interface Timestamped {
createdAt: Date;
updatedAt: Date;
}
interface Identifiable {
id: string;
}
interface User extends Identifiable, Timestamped {
name: string;
email: string;
}
const user: User = {
id: "U001",
name: "Alice",
email: "alice@test.com",
createdAt: new Date(),
updatedAt: new Date()
};
5. Interface merging
Declaration merging
아래 코드는 typescript를 사용한 구현 예제입니다. 클래스를 정의하여 데이터와 기능을 캡슐화하며. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
interface User {
name: string;
}
interface User {
age: number;
}
const user: User = {
name: "Alice",
age: 25
};
Augmenting globals
아래 코드는 typescript를 사용한 구현 예제입니다. 클래스를 정의하여 데이터와 기능을 캡슐화하며. 코드를 직접 실행해보면서 동작을 확인해보세요.
interface Window {
myCustomProperty: string;
}
window.myCustomProperty = "Hello!";
console.log(window.myCustomProperty);
6. Classes and interfaces
implements
다음은 typescript를 활용한 상세한 구현 코드입니다. 클래스를 정의하여 데이터와 기능을 캡슐화하며. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
interface Animal {
name: string;
makeSound(): void;
}
class Dog implements Animal {
name: string;
constructor(name: string) {
this.name = name;
}
makeSound() {
console.log("Woof!");
}
}
const dog = new Dog("Buddy");
dog.makeSound();
Multiple interfaces
다음은 typescript를 활용한 상세한 구현 코드입니다. 클래스를 정의하여 데이터와 기능을 캡슐화하며. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
interface Flyable {
fly(): void;
}
interface Swimmable {
swim(): void;
}
class Duck implements Flyable, Swimmable {
fly() {
console.log("Flying!");
}
swim() {
console.log("Swimming!");
}
}
const duck = new Duck();
duck.fly();
duck.swim();
7. Interface vs type alias
Comparison
| Feature | Interface | Type alias |
|---|---|---|
| Object shapes | ✅ | ✅ |
| Union / intersection | ❌ (use type) | ✅ |
| Extension | extends | & |
| Declaration merging | ✅ | ❌ |
| Primitive aliases | ❌ | ✅ |
Examples
다음은 typescript를 활용한 상세한 구현 코드입니다. 클래스를 정의하여 데이터와 기능을 캡슐화하며. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
interface User {
name: string;
}
interface User {
age: number;
}
type Person = {
name: string;
};
type ID = string | number;
type Status = "active" | "inactive";
type Employee = Person & {
employeeId: string;
};
8. Hands-on examples
Example 1: API response
다음은 typescript를 활용한 상세한 구현 코드입니다. 클래스를 정의하여 데이터와 기능을 캡슐화하며, 비동기 처리를 통해 효율적으로 작업을 수행합니다, 에러 처리를 통해 안정성을 확보합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
interface ApiResponse<T> {
success: boolean;
data: T;
error?: string;
timestamp: Date;
}
interface User {
id: string;
name: string;
email: string;
}
async function fetchUser(id: string): Promise<ApiResponse<User>> {
try {
const response = await fetch(`/api/users/${id}`);
const data = await response.json();
return {
success: true,
data,
timestamp: new Date()
};
} catch (error) {
return {
success: false,
data: null as any,
error: "Request failed",
timestamp: new Date()
};
}
}
Example 2: Form validation
다음은 typescript를 활용한 상세한 구현 코드입니다. 클래스를 정의하여 데이터와 기능을 캡슐화하며, 함수를 통해 로직을 구현합니다, 에러 처리를 통해 안정성을 확보합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
interface FormField {
value: string;
error: string | null;
touched: boolean;
}
interface LoginForm {
email: FormField;
password: FormField;
}
const form: LoginForm = {
email: {
value: "",
error: null,
touched: false
},
password: {
value: "",
error: null,
touched: false
}
};
function validateEmail(email: string): string | null {
const regex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
return regex.test(email) ? null : "Invalid email format";
}
form.email.value = "alice@test.com";
form.email.error = validateEmail(form.email.value);
form.email.touched = true;
Example 3: Event handlers
다음은 typescript를 활용한 상세한 구현 코드입니다. 클래스를 정의하여 데이터와 기능을 캡슐화하며. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
interface ClickEvent {
x: number;
y: number;
button: "left" | "right";
}
interface EventHandler<T> {
(event: T): void;
}
const handleClick: EventHandler<ClickEvent> = (event) => {
console.log(`Click: (${event.x}, ${event.y}), button: ${event.button}`);
};
handleClick({ x: 100, y: 200, button: "left" });
Summary
Takeaways
- Interface: describe object structure
- Optional:
? - Readonly:
readonly - Extension:
extends(multiple allowed) - Implementation:
implements(multiple allowed) - Merging: declaration merging
When to use interfaces
- Object models
- Class contracts
- Augmenting libraries
- API response types