함수의 매개변수와 반환값에 타입을 지정하는 기본기부터, 오버로드까지 단계별로 정리합니다.
1. 함수의 반환 타입 지정
함수 선언 시 괄호 뒤에 반환 타입을 명시합니다. 명시한 타입과 실제 반환값이 다르면 컴파일 에러가 발생합니다.
// number를 반환
function add1(num1: number, num2: number): number {
return num1 + num2;
}
// 반환값이 없는 함수
function add2(num1: number, num2: number): void {
console.log(num1 + num2);
}
// boolean을 반환
function isAdult(age: number): boolean {
return age > 19;
}
⚠️ 반환 타입을 number로 지정해놓고 아무것도 return하지 않으면 에러가 발생합니다. 반환값이 없다면 void를 사용하세요.
2. 선택적 매개변수 (?)
매개변수에 ?를 붙이면 해당 인자를 넘기지 않아도 됩니다.
function hello(name?: string): string {
return `Hello, ${name || "world"}`;
}
hello(); // "Hello, world"
hello("Sam"); // "Hello, Sam"
name이 전달되지 않으면 undefined가 되므로, 기본값 처리를 함께 해주는 것이 안전합니다.
기본값으로 대체하기
? 대신 매개변수에 직접 기본값을 넣을 수도 있습니다. 이 경우 타입은 기본값에서 자동 추론됩니다.
function hello2(name = "world"): string {
return `Hello, ${name}`;
}
hello2(); // "Hello, world"
hello2("Sam"); // "Hello, Sam"
3. 선택적 매개변수의 위치 주의점
선택적 매개변수는 반드시 필수 매개변수 뒤에 와야 합니다. 앞에 두면 에러가 발생합니다.
// ❌ Error — 선택적 매개변수가 필수 매개변수 앞에 있음
function hello3(age?: number, name: string): string {
if (age !== undefined) {
return `Hello, ${name}. You are ${age}`;
}
return `Hello, ${name}`;
}
만약 선택적 매개변수를 앞에 두고 싶다면, ? 대신 유니온 타입으로 undefined를 명시적으로 허용합니다.
// ✅ OK — undefined를 명시적으로 허용
function hello3(age: number | undefined, name: string): string {
if (age !== undefined) {
return `Hello, ${name}. You are ${age}`;
}
return `Hello, ${name}`;
}
hello3(undefined, "Sam"); // "Hello, Sam"
hello3(30, "Sam"); // "Hello, Sam. You are 30"
💡 ?는 "안 넘겨도 된다"는 의미이고, number | undefined는 "반드시 넘기되 undefined도 허용한다"는 의미입니다. 호출 시 인자 생략 가능 여부에 차이가 있습니다.
4. 나머지 매개변수 (Rest Parameters)
매개변수 개수가 유동적일 때 ... 스프레드 문법으로 배열 타입을 지정합니다.
function add(...nums: number[]) {
return nums.reduce((result, num) => result + num, 0);
}
add(1, 2, 3); // 6
add(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); // 55
nums는 전달된 모든 인자를 number[] 배열로 받아 처리합니다.
5. this 타입 지정
TypeScript에서는 함수의 첫 번째 매개변수 위치에 this의 타입을 명시할 수 있습니다. 이 매개변수는 실제로 전달하는 인자가 아니라, this가 어떤 타입인지 컴파일러에게 알려주는 역할입니다.
interface User {
name: string;
}
const Sam: User = { name: 'Sam' };
function showName(this: User, age: number, gender: 'm' | 'f') {
console.log(this.name, age, gender);
}
const a = showName.bind(Sam);
a(30, 'm'); // "Sam" 30 "m"
💡 this: User는 호출 시 넘기는 인자가 아닙니다. bind, call, apply로 바인딩된 this의 타입을 검사하기 위한 TypeScript 전용 문법입니다.
6. 함수 오버로드 (Function Overload)
전달받은 매개변수의 타입이나 개수에 따라 다른 반환 타입을 가져야 할 때 사용합니다.
문제 상황
interface User {
name: string;
age: number;
}
function join(name: string, age: number | string): User | string {
if (typeof age === "number") {
return { name, age };
} else {
return "나이는 숫자로";
}
}
const sam: User = join("Sam", 30); // ❌ Error — User | string을 User에 할당 불가
const jane: string = join("Jane", "30"); // ❌ Error — User | string을 string에 할당 불가
함수 내부 로직상 age가 number면 User를, string이면 string을 반환하지만, TypeScript는 반환 타입을 User | string으로밖에 추론하지 못합니다.
오버로드로 해결
함수 본체 위에 오버로드 시그니처를 선언하면, 입력 타입에 따라 반환 타입을 정확히 매핑할 수 있습니다.
function join(name: string, age: number): User; // 시그니처 1
function join(name: string, age: string): string; // 시그니처 2
function join(name: string, age: number | string): User | string {
if (typeof age === "number") {
return { name, age };
} else {
return "나이는 숫자로";
}
}
const sam: User = join("Sam", 30); // ✅ OK — number를 넘기면 User 반환
const jane: string = join("Jane", "30"); // ✅ OK — string을 넘기면 string 반환
💡 오버로드 시그니처는 실제 구현이 아닌 타입 정보만 제공합니다. 마지막에 오는 구현부가 모든 시그니처를 포괄할 수 있어야 합니다.
한눈에 보기
기능 문법 설명
| 반환 타입 | function fn(): number | 반환값의 타입 명시 |
| void | function fn(): void | 반환값 없음 |
| 선택적 매개변수 | name?: string | 인자 생략 가능 |
| 기본값 | name = "world" | 생략 시 기본값 사용 |
| 유니온 허용 | age: number | undefined | 앞쪽에 선택적 매개변수 배치 시 |
| 나머지 매개변수 | ...nums: number[] | 가변 인자를 배열로 수집 |
| this 타입 | this: User | this의 타입 명시 (실제 인자 아님) |
| 오버로드 | 시그니처 + 구현부 | 입력에 따라 반환 타입 분기 |
'프론트' 카테고리의 다른 글
| TypeScript 클래스(Class) (0) | 2026.04.11 |
|---|---|
| TypeScript 리터럴 · 유니온 · 교차 타입 정리 (0) | 2026.04.11 |
| TypeScript 인터페이스(Interface) (0) | 2026.04.11 |
| TypeScript 기초 타입 정리 (0) | 2026.04.11 |
| 타입스크립트를 사용하는 이유 (0) | 2026.04.11 |