Typescript | 함수 타입, 함수 호환, 오버로드, 사용자 정의 타입 가드

seunghyun·2025년 1월 19일
0

web

목록 보기
1/4

Typescipt 함수

javascript의 함수도 사실은 객체다. 그래서 {}로 선언하는 것임.

자바스크립트에서 함수는 일급 객체이다 => 함수를 객체와 동일하게 사용할 수 있다. 즉 아래와 같은 작업을 할 수 있다.

객체를 다루듯이 함수를 변수에 할당
함수를 다른 함수로 전달
함수에서 함수로 반환
객체와 프로토타입에 할당
함수에 프로퍼티에 기록, 기록된 프로퍼티를 읽기

https://velog.io/@rlaclghks123/TypeScript-%ED%95%A8%EC%88%98


함수 타입 정의 중 나머지 매개변수 사용하는 법
https://ts.winterlood.com/d6b17fad-0a06-4733-89e5-c8fcaf194ed5

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) // ❌

rest 매개변수: https://reactjs.winterlood.com/4e81b92b-4097-4fd8-8c67-09a7588c94d6#c027776dc2ea440d9867381b8ec296fe


함수 타입 표현식은 여러개의 함수가 동일한 타입을 갖는 경우에 요긴하게 사용된다.

https://www.typescriptlang.org/docs/handbook/2/functions.html#function-type-expressions

반드시 타입 별칭과 함께 사용되어야 하는 것은 아니다. 다음과 같이 그냥 함수 타입 표현식을 타입 주석에 사용해도 문제는 없다.

// before
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
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;

호출 호출 시그니쳐(Call Signature)는 함수 타입 표현식과 동일하게 함수의 타입을 별도로 정의하는 방식이다.

type Operation2 = {
  (a: number, b: number): number;
  name: string; // 하이브리드 타입
};

const add2: Operation2 = (a, b) => a + b;
(...)

add2(1, 2);
add2.name;

이런 식으로 타입을 마들면 이 타입을 갖는 변수를 마치 객체로도, 함수로도 쓸 수 있다고 해서 이렇게 만드는 타입을 하이브리드 타입이라고도 부른다.


함수 타입의 호환성
https://ts.winterlood.com/267b10cd-5f23-4689-b2f4-0b7420523a64

함수 타입의 호환성이란 특정 함수 타입을 다른 함수 타입으로 괜찮은지 판단하는 것을 의미한다.
다음 2가지 기준으로 함수 타입의 호환성을 판단하게 된다.

  • 두 함수의 반환값 타입이 호환되는가?
  • 두 함수의 매개변수의 타입이 호환되는가?, + 매개변수 개수 같은지 다른지

함수 반환값 기준일 때와 달리, 매개변수 기준일 때는 업캐스팅 호환이 적용이 안됨
(number <-업 캐스팅 number literal) 이렇게 업캐스팅이 안됨
근데 또 다운 캐스팅은 됨
???

즉 매개변수 기준으로 보면 뭐든간에 소실되는 경우가 안됨 (업캐스팅이거나 개수가 많은 쪽에서 적은 쪽으로 가거나)


함수 오버로딩

C에서 익숙한 개념이다 히히
근데 JS에선 지원이 안되고 TS에선 지원이 됨

// 버전들 -> 오버로드 시그니쳐
function func(a: number): void;
function func(a: number, b: number, c: number): void;

// 실제 구현부 -> 구현 시그니쳐
function func(a: number, b?: number, c?: number) {
  if (typeof b === "number" && typeof c === "number") {
    console.log(a + b + c);
  } else {
    console.log(a * 20);
  }
}

func(1);        // ✅ 버전 1 - 오버로드 시그니쳐
func(1, 2);     // ❌ 
func(1, 2, 3);  // ✅ 버전 3 - 오버로드 시그니쳐

구현 시그니쳐의 매개변수 타입은 모든 오버로드 시그니쳐와 호환되도록 만들어야 한다. 따라서 위 코드에서는 매개변수 b와 c를 선택적 매개변수로 만들어 매개변수를 하나만 받는 첫번째 오버로드 시그니쳐와도 호환되도록 만들어 주었다.


사용자 정의 타입 가드

isDog 함수는 매개변수로 받은 값이 Dog 타입이라면 true 아니라면 false를 반환한다. 이때 반환값의 타입으로 animal is Dog 를 정의하면 이 함수가 true를 반환하면 조건문 내부에서는 이 값이 Dog 타입임을 보장한다는 의미가 된다. 따라서 warning 함수에서 isDog 함수를 호출해 매개변수의 값이 Dog 타입인지 확인하고 타입을 좁힐 수 있다.

(...)

// Dog 타입인지 확인하는 타입 가드
function isDog(animal: Animal): animal is Dog {
  return (animal as Dog).isBark !== undefined;
}

// Cat 타입인지 확인하는 타입가드
function isCat(animal: Animal): animal is Cat {
  return (animal as Cat).isScratch !== undefined;
}

function warning(animal: Animal) {
  if (isDog(animal)) {
    console.log(animal.isBark ? "짖습니다" : "안짖어요");
  } else {
    console.log(animal.isScratch ? "할큅니다" : "안할퀴어요");
  }
}
profile
game client programmer

0개의 댓글