Function

4개의 게시글

TypeScript

[TypeScript] 함수 오버로딩 (Function Overloading)

November 27, 2025

타입스크립트에서는 하나의 함수가 매개변수의 개수나 타입에 따라 다르게 동작하도록 만들 수 있다. 이를 함수 오버로딩(Function Overloading) 이라고 한다. C이나 Java 같은 언어에서는 흔한 기능이지만, 자바스크립트는 원래 이를 지원하지 않는다. 하지만 타입스크립트에서는 오버로드 시그니처를 통해 이 기능을 흉내 낼 수 있다. 1. 함수 오버로딩의 구조 함수 오버로딩을 구현하려면 크게 두 단계가 필요하다. 1. 오버로드 시그니처 (Overload Signature): 함수의 껍데기. 호출 가능한 버전을 정의한다. 2. 구현 시그니처 (Implementation Signature): 함수의 알맹이. 실제 로직을 구현한다. 예시 시나리오 하나의 함수 func를 만드는데, 다음 두 가지 상황을 모두 처리하고 싶다고 가정해보자. - Ver 1 (매개변수 1개): 숫자를 하나 받으면 x 20 한 값을 출력. - Ver 2 (매개변수 3개): 숫자를 세 개 받으면 모두 더한 값을 출력. --- 2. 오버로드 시그니처 (선언부) 먼저 함수가 어떤 형태의 매개변수를 받을 수 있는지 선언만 해둔다. 구현부({}) 없이 작성한다. TypeScript // 버전 1: 매개변수 1개 function func(a: number): void; // 버전 2: 매개변수 3개 function func(a: number, b: number, c: number): void; 이제 컴파일러는 func 함수가 인자를 1개 받거나, 3개 받는 경우만 허용한다는 것을 알게 된다. --- 3. 구현 시그니처 (구현부) 이제 실제로 함수가 어떻게 동작할지 코드를 작성해야 한다. 이때 중요한 점은 구현 시그니처의 매개변수는 위에서 정의한 모든 오버로드 시그니처를 커버할 수 있어야 한다는 것이다. TypeScript // 실제 구현부 function func(a: number, b?: number, c?: number) { if (typeof b === "number" && typeof c === "number") { // 매개변수가 3개 들어온 경우 (Ver 2) console.log(a + b + c); } else { // 매개변수가 1개 들어온 경우 (Ver 1) console.log(a 20); } } 💡 왜 b와 c가 선택적 매개변수(?)여야 할까? 첫 번째 오버로드 시그니처(func(a: number))는 b와 c를 받지 않는다. 따라서 구현부에서 b와 c를 필수값으로 정의하면 첫 번째 버전과 호환되지 않아 에러가 발생한다. 모든 버전을 포용하기 위해 유연하게 정의해야 한다. --- 4. 함수 호출 및 결과 이제 정의한 함수를 사용해보자. TypeScript func(1); // ✅ 버전 1 호출 -> 20 출력 func(1, 2, 3); // ✅ 버전 3 호출 -> 6 출력 // func(1, 2); // ❌ 에러 발생! func(1, 2)는 인자를 2개 넘겼다. 우리는 인자 1개짜리 버전과 3개짜리 버전만 만들었지, 2개짜리 오버로드 시그니처는 만들지 않았다. 따라서 타입스크립트는 이를 에러로 잡는다. --- 요약 1. 함수 오버로딩: 매개변수의 형태에 따라 다르게 동작하는 함수를 만드는 문법. 2. 오버로드 시그니처: 함수의 매개변수와 반환값 타입만 정의한 선언부. (여러 개 가능) 3. 구현 시그니처: 실제 로직이 있는 부분. 모든 오버로드 시그니처와 호환되어야 하므로 매개변수 타입을 유연하게(Optional 등) 설정해야 한다.

TypeScriptStudyFunctionOverloading
TypeScript

[TypeScript] 함수 타입의 호환성

November 27, 2025

타입스크립트에서 함수 타입의 호환성이란, 특정 함수 타입을 다른 함수 타입으로 취급해도 괜찮은지(할당 가능한지)를 판단하는 것을 말한다. 함수 타입의 호환성은 다음 2가지 기준으로 체크한다. 1. 반환값(Return) 의 타입이 호환되는가? 2. 매개변수(Parameter) 의 타입이 호환되는가? 하나씩 자세히 살펴보자. 1. 기준 1: 반환값 타입이 호환되는가? 반환값은 우리가 아는 일반적인 객체 타입의 호환성 원칙(공변성)과 같다. 즉, A의 반환값이 B의 반환값의 서브 타입(자식)이어야 호환된다. (업캐스팅 가능) TypeScript type A = () => number; type B = () => 10; let a: A = () => 10; let b: B = () => 10; a = b; // ✅ OK (number는 10을 포함함) // b = a; // ❌ NO (10은 number 전체를 포함하지 못함) 변수 a는 number를 반환하기를 기대하고, b 함수는 10을 반환한다. 10은 number에 속하므로 호환된다. 반대는 성립하지 않는다. --- 2. 기준 2: 매개변수의 타입이 호환되는가? 매개변수의 호환성은 매개변수의 개수가 같은지 다른지에 따라 판단 기준이 달라진다. 2-1. 매개변수의 개수가 같을 때 (반공변성) 이 부분이 가장 헷갈리는 부분이다. 결론부터 말하면 반환값과는 반대로, 할당하려는 함수의 매개변수 타입이 더 상위(슈퍼) 타입이어야 호환된다. 일반적인 객체 호환성과 반대되는 개념이라 반공변성(Contravariance) 이라고도 부른다. TypeScript type C = (value: number) => void; type D = (value: 10) => void; let c: C = (value) => {}; let d: D = (value) => {}; // c = d; // ❌ NO (number <-- 10 : 업캐스팅 같지만 함수 매개변수에서는 안 됨) d = c; // ✅ OK (10 --> number : 다운캐스팅 같지만 함수 매개변수에서는 됨) 왜 반대일까? (객체 예시로 이해하기) Animal(부모)과 Dog(자식) 타입을 예로 들어보자. TypeScript type Animal = { name: string }; type Dog = { name: string; color: string }; let animalFunc = (animal: Animal) => { console.log(animal.name); }; let dogFunc = (dog: Dog) => { console.log(dog.name); console.log(dog.color); }; // animalFunc = dogFunc; // ❌ 불가능 dogFunc = animalFunc; // ✅ 가능 - 불가능한 이유 (animalFunc = dogFunc): animalFunc는 Animal 타입의 인수를 받는다. 만약 여기에 dogFunc를 할당해버리면, dogFunc는 내부적으로 dog.color를 찾으려 할 것이다. 하지만 Animal 타입에는 color가 없으므로 런타임 에러가 발생할 수 있다. - 가능한 이유 (dogFunc = animalFunc): dogFunc는 Dog 타입의 인수를 받는다. 여기에 animalFunc를 할당하면, animalFunc는 들어온 인수에서 name만 사용한다. Dog 타입에는 name이 보장되어 있으므로 안전하다. > 결론: 매개변수 개수가 같을 때는 매개변수 타입이 더 넓은(슈퍼 타입인) 함수를 대입해야 안전하다. > --- 2-2. 매개변수의 개수가 다를 때 매개변수의 개수가 다를 때는 비교적 단순하다. 매개변수의 개수가 더 적은 함수는 호환된다. (단, 타입은 같아야 함) TypeScript type Func1 = (a: number, b: number) => void; type Func2 = (a: number) => void; let func1: Func1 = (a, b) => {}; let func2: Func2 = (a) => {}; func1 = func2; // ✅ OK (인자 2개 받는 자리에 1개 받는 함수 넣기 가능) // func2 = func1; // ❌ NO (인자 1개 받는 자리에 2개 필요한 함수 넣기 불가) 자바스크립트/타입스크립트에서는 함수에 정의된 매개변수보다 더 많은 인자를 넘겨도, 함수가 알아서 무시하고 실행되기 때문에 이는 안전한 동작으로 간주된다. --- 요약 1. 반환값: 일반적인 객체와 똑같다. (자식 타입을 부모 타입에 할당 가능 - 업캐스팅) 2. 매개변수 (개수 같음): 일반적인 객체와 반대다. (부모 타입을 자식 타입에 할당 가능 - 반공변성) 3. 매개변수 (개수 다름): 매개변수가 더 적은 쪽을 할당할 수 있다.

TypeScriptStudyFunctionTypeCompatibility
TypeScript

[TypeScript] 함수 타입 표현식과 호출 시그니처

November 27, 2025

타입스크립트에서는 함수를 선언할 때 매개변수 옆에 일일이 타입을 적는 방식 외에도, 함수의 타입만 따로 정의해두고 재사용하는 방법을 제공한다. 이를 가능하게 하는 두 가지 방법, 함수 타입 표현식과 호출 시그니처에 대해 알아본다. 1. 함수 타입 표현식 (Function Type Expression) 함수 타입 표현식은 타입 별칭(type)을 사용하여 함수의 타입을 별도로 정의하는 문법이다. 1-1. 기본 문법 화살표 함수와 비슷한 형태를 띤다. (매개변수 타입) => 반환값 타입 형식으로 작성한다. TypeScript // 함수 타입 정의 type Add = (a: number, b: number) => number; // 함수 구현 (타입 별칭 사용) const add: Add = (a, b) => a + b; 이렇게 하면 실제 함수 구현부(const add ...)에서는 매개변수의 타입을 생략해도 된다. 이미 Add 타입에서 정의했기 때문에 타입스크립트가 타입을 추론할 수 있기 때문이다. 1-2. 사용하는 이유 (재사용성) 함수 타입 표현식은 여러 함수가 동일한 타입을 가질 때 매우 유용하다. 예를 들어 계산기 기능을 만든다고 가정해 보자. 더하기, 빼기, 곱하기, 나누기 모두 (숫자, 숫자) => 숫자 형태를 가진다. Before: 일일이 정의하는 경우 TypeScript const add = (a: number, b: number) => a + b; const sub = (a: number, b: number) => a - b; const multiply = (a: number, b: number) => a b; const divide = (a: number, b: number) => a / b; 코드가 길어지고 중복이 많다. After: 함수 타입 표현식 사용 TypeScript // 공통 타입 정의 type Operation = (a: number, b: number) => number; const add: Operation = (a, b) => a + b; const sub: Operation = (a, b) => a - b; const multiply: Operation = (a, b) => a b; const divide: Operation = (a, b) => a / b; 코드가 훨씬 간결해졌다. 만약 나중에 타입 정의를 수정해야 한다면 Operation 타입 하나만 수정하면 되므로 유지보수성도 좋아진다. > 참고: 타입 별칭 없이 인라인으로 사용할 수도 있다. > > > const add: (a: number, b: number) => number = (a, b) => a + b; > --- 2. 호출 시그니처 (Call Signature) 호출 시그니처는 함수 타입 표현식과 동일한 기능을 하지만, 객체 리터럴 문법을 사용하여 정의하는 방식이다. 2-1. 기본 문법 중괄호 {}를 열고, 그 안에 (매개변수): 반환값 형태로 작성한다. (화살표 => 대신 콜론 :을 사용함에 주의하자) TypeScript type Operation2 = { (a: number, b: number): number; }; const add2: Operation2 = (a, b) => a + b; const sub2: Operation2 = (a, b) => a - b; const multiply2: Operation2 = (a, b) => a b; const divide2: Operation2 = (a, b) => a / b; 2-2. 왜 객체처럼 정의할까? (하이브리드 타입) 자바스크립트에서는 함수도 객체이다. 즉, 함수에 프로퍼티를 추가해서 사용할 수 있다. 호출 시그니처를 사용하면 함수이면서 동시에 일반 객체처럼 프로퍼티를 가지는 타입을 정의할 수 있다. 이를 하이브리드 타입이라고 부른다. TypeScript type Operation2 = { (a: number, b: number): number; // 1. 함수로서 호출 가능 name: string; // 2. 일반 객체 프로퍼티 보유 }; const add2: Operation2 = (a, b) => a + b; // 하이브리드 타입 구현을 위해 프로퍼티 추가 add2.name = "Add Function"; console.log(add2(1, 2)); // 3 (함수로 사용) console.log(add2.name); // "Add Function" (객체로 사용) --- 요약 1. 함수 타입 표현식: type Name = (params) => returnType 형태로, 함수의 타입을 간결하게 정의하고 재사용할 때 사용한다. 2. 호출 시그니처: type Name = { (params): returnType } 형태로, 객체 문법을 사용해 정의한다. 3. 하이브리드 타입: 호출 시그니처를 사용하면 함수 기능과 객체 프로퍼티를 동시에 가지는 타입을 정의할 수 있다.

TypeScriptStudyFunctionTypeDefinition
TypeScript

[TypeScript] 함수(Function) 타입 정의하기

November 27, 2025

자바스크립트에서 함수를 설명할 때 가장 중요한 것은 "어떤 매개변수를 받아서, 어떤 값을 반환하는가" 이다. 타입스크립트도 마찬가지다. 단지 그 설명에 타입만 추가하면 된다. 1. 기본적인 함수 타입 정의 함수의 타입은 매개변수의 타입과 반환값의 타입으로 결정된다. 1-1. 함수 선언식 매개변수 뒤에 타입을 적고, 소괄호 뒤에 반환값의 타입을 적는다. TypeScript function func(a: number, b: number): number { return a + b; } 💡 반환값 타입 추론 타입스크립트는 return문을 보고 반환값의 타입을 자동으로 추론할 수 있다. 따라서 반환 타입은 생략해도 무방하다. TypeScript function func(a: number, b: number) { return a + b; // 자동으로 number 반환으로 추론됨 } 1-2. 화살표 함수 화살표 함수도 선언식과 동일한 방식으로 타입을 정의한다. TypeScript const add = (a: number, b: number): number => a + b; // 반환값 타입 생략 가능 const add2 = (a: number, b: number) => a + b; --- 2. 매개변수 다루기 함수의 매개변수를 정의할 때 사용할 수 있는 유용한 기능들이다. 2-1. 매개변수 기본값 (Default Parameter) 매개변수에 기본값이 설정되어 있다면, 타입스크립트가 해당 기본값을 기준으로 타입을 자동으로 추론한다. TypeScript function introduce(name = "조태민") { console.log(name : ${name}); } // introduce(1); // ❌ 오류: string 타입에 number 할당 불가 만약 기본값과 다른 타입으로 명시하거나, 다른 타입의 값을 인수로 전달하면 에러가 발생한다. 2-2. 선택적 매개변수 (Optional Parameter) 매개변수가 있어도 되고 없어도 되는 경우, 변수명 뒤에 물음표(?)를 붙여 선택적 매개변수로 만들 수 있다. TypeScript function introduce(name = "조태민", tall?: number) { console.log(name : ${name}); // tall은 number | undefined 타입이 됨 if (typeof tall === "number") { console.log(tall : ${tall + 10}); } } introduce("조태민", 178); // ✅ introduce("조태민"); // ✅ (tall 생략 가능) 주의할 점: 1. 선택적 매개변수의 타입은 자동으로 undefined와 유니온 된 타입(Type | undefined)이 된다. 따라서 사용 시 타입 좁히기가 필요할 수 있다. 2. 선택적 매개변수는 필수 매개변수보다 앞에 올 수 없다. 항상 뒤에 배치해야 한다. TypeScript // ❌ 오류 발생: 필수 매개변수(age)는 선택적 매개변수(tall) 뒤에 올 수 없음 // function introduce(name = "조태민", tall?: number, age: number) {} --- 3. 나머지 매개변수 (Rest Parameter) 가변적인 개수의 인수를 배열 형태로 받을 때 사용하는 나머지 매개변수(...rest)의 타입 정의 방법이다. 3-1. 배열로 정의하기 일반적으로는 특정 타입의 배열(Type[])로 정의한다. TypeScript function getSum(...rest: number[]) { let sum = 0; rest.forEach((it) => (sum += it)); return sum; } getSum(1, 2, 3); // [1, 2, 3]으로 전달됨 3-2. 튜플로 정의하기 (개수 제한) 만약 인수의 개수를 정확히 제한하고 싶다면 튜플 타입을 사용할 수 있다. TypeScript // 정확히 숫자 3개만 받을 수 있음 function getSum(...rest: [number, number, number]) { let sum = 0; rest.forEach((it) => (sum += it)); return sum; } getSum(1, 2, 3); // ✅ // getSum(1, 2, 3, 4); // ❌ 오류: 3개만 허용됨 --- 요약 1. 기본 정의: 매개변수와 반환값의 타입을 명시한다. (반환값은 추론 가능) 2. 기본값: param = value 형태이며, 타입이 자동 추론된다. 3. 선택적 매개변수: param?: type 형태이며, 필수 매개변수 뒤에 와야 한다. 4. 나머지 매개변수: ...rest: type[] 형태이며, 튜플을 쓰면 개수 제한이 가능하다.

TypeScriptStudyFunction기초문법