본문 바로가기
C.W.K.
Stream
Lesson 01 of 05 · published

함수 타입: 들어오는 값과 나가는 값의 계약

~10 min · functions, parameters, return-types, function-types

Level 0Curious
0 XP0/93 lessons0/23 achievements
0/100 XP to next level100 XP to go0% complete
"함수 타입은 무엇을 받고, 무엇을 돌려주며, 무엇을 생략할 수 있는지를 한 줄에 묶은 계약이야."

함수에 타입을 붙이는 네 가지 모양

가장 흔한 형태는 매개변수와 반환값에 곧바로 타입을 적는 거야. function greet(name: string): string처럼 읽으면 돼. 같은 함수 모양이 반복되면 type Greeter = (name: string) => string처럼 별칭으로 뽑아 재사용할 수 있어.

객체 안의 동작은 interface의 메서드 문법으로 적을 수 있고, 함수 자체에 속성도 붙는 호출 가능한 객체라면 호출 시그니처를 가진 interface를 쓸 수 있어. 네 문법이 서로 다른 종류의 함수를 만드는 것은 아니야. 어느 관계를 읽기 좋게 드러내느냐가 선택을 가른다.

필수, 선택, 기본값, 나머지 매개변수

선택 매개변수 name?: string은 함수 안에서 string 또는 undefined야. 기본값이 있는 name = 'anon'은 생략되면 값이 채워지므로 함수 안에서 string으로 좁혀져. 나머지 매개변수 ...names: string[]는 남은 인자를 배열로 모아.

필수 매개변수 뒤에 선택 매개변수를 두고, 나머지 매개변수는 마지막에 놓는 순서를 지켜야 해. 중간 인자를 자주 생략해야 한다면 위치 매개변수를 늘이기보다 옵션 객체가 더 잘 읽힐 수 있어.

호환성은 호출자의 안전으로 판단해

두 함수 타입을 비교할 때는 호출자가 제공하는 인자와 기대하는 반환값을 기준으로 봐. 두 인자를 줄 자리에는 한 인자만 쓰는 함수도 들어갈 수 있어. 추가 인자를 무시하면 되니까. 반대로 세 번째 인자를 반드시 요구하는 함수는 두 인자만 주는 자리에 넣을 수 없어.

반환값은 더 구체적인 타입을 돌려줘도 괜찮아. 호출자가 string을 기대할 때 정확한 리터럴 'ready'를 반환하면 약속을 만족해. 함수 매개변수의 공변성과 반공변성 규칙은 복잡해 보이지만, ‘이 자리에 들어간 함수를 호출해도 안전한가’를 물으면 방향을 잃지 않아.

함수 타입은 구현보다 호출 가능성을 설명해. 매개변수는 호출자가 무엇을 줄지, 반환값은 호출자가 무엇을 믿을지를 기준으로 읽어.

피파의 고백

함수 호환성 오류를 처음 보면 문장이 길어서 겁부터 나. 그런데 ‘호출자가 몇 개를 주고 무엇을 기대하지?’ 두 질문으로 줄이면 대부분 금방 풀려. 어려운 용어는 규칙에 이름을 붙인 것이고, 안전성의 방향이 본체야.

Code

함수 타입의 4가지 모양·typescript
// 함수 타이핑 4가지 방법.

// 1. Inline
function greet(name: string): string {
  return `hi ${name}`;
}

// 2. 함수-타입 alias
type Greeter = (name: string) => string;
const hello: Greeter = (n) => `hello ${n}`;     // alias 에서 parameter 타입 추론

// 3. Interface 의 method 단축형
interface API {
  greet(name: string): string;
}

// 4. Call signature
interface Callable {
  (name: string): string;       // 이 interface 전체가 함수
  description: string;          // 그리고 property 도 있어
}

const c: Callable = Object.assign((n: string) => `hi ${n}`, { description: 'greeter' });
Modifier + 호환성·typescript
// Optional, default, rest — 그리고 유지해야 할 순서.

function request(
  url: string,                              // 필수
  method: 'GET' | 'POST' = 'GET',           // default
  headers?: Record<string, string>,         // optional
  ...flags: string[]                        // rest — 마지막 필수
) {
  // 안: url 은 string, method 는 'GET' | 'POST', headers 는 Record | undefined, flags 는 string[]
}

request('/api');                                 // ✅
request('/api', 'POST');                          // ✅
request('/api', 'POST', { 'x-key': 'abc' });     // ✅
request('/api', 'POST', undefined, '-v', '--retry');  // ✅ rest 가 varargs 받음

// 함수-타입 호환성 — 규칙 in action.
type Strict = (a: number, b: string) => void;
const f: Strict = (a) => {};                      // ✅ 더 적은 parameter 받음
const g: Strict = (a, b, c: boolean) => {};       // ❌ slot 이 주는 것보다 더 요구

External links

Exercise

나머지 숫자 인자를 더하는 sum과 두 값을 합치는 Reducer<T> 함수 타입을 만들어. 매개변수가 세 개인 함수를 두 자리 계약에 넣었을 때 왜 거절되는지 설명해.
Hint
매개변수가 적은 함수는 더 많은 인자를 받는 호출 자리에서 쓸 수 있어. 반대는 호출자가 필요한 세 번째 값을 주지 않을 수 있으므로 안전하지 않아.

Progress

Progress is local-only — sign in to sync across devices.
이 페이지에서 버그를 발견하셨거나 피드백이 있으세요?문제 신고

댓글 0

🔔 답글 알림 (로그인 필요)
로그인댓글을 남기려면 로그인해 주세요.

아직 댓글이 없어요. 첫 댓글을 남겨보세요.