[한입챌린지]타입스크립트 DAY7

Lina Hongbi Ko·2025년 3월 13일
0
post-thumbnail

DAY7

2025년 3월 2일

✨ 함수 타입

  • 함수를 설명하는 가장 좋은 방법

    • 어떤 매개변수를 받고, 어떤 결과값을 반환하는지 이야기
    • 어떤 [타입의] 매개변수를 받고, 어떤 [타입의] 결과값을 반환하는지 이야기
    function func(a: number, b: number) {
      return a + b;
    }
  • 화살표 함수의 타입을 정의하는 방법

    const add = (a: number, b: number) => a + b;
  • 함수의 매개변수

    • 함수의 매개변수에 기본값을 설정해 그 기본값의 타입을 추론할 수 있도록 할 수 있음

      • 주의할 점1: 기본값과 다른 타입을 정의하면 안됨
        e.g) name: number = '이정환' => X
      • 주의할 점2: 함수를 호출할때 자동 추론된 매개변수의 타입과 다른 타입의 값을 인수로 전달하면 오류 발생
        e.g) introduce(1) => X
    • 함수의 매개변수를 하나 더 추가해서 타입을 정의해주면 두 개의 인수로 함수를 호출해야 함

      • 그런데 인수를 하나를 생략해서 함수를 호출하는 경우에는 오류가 발생함 -> 이럴때에는 매개변수를 '선택적 매개변수'로 설정해주면 됨
        e.g) tall?: number -> tall: number | undefined 으로 추론함
      • 그리고나서, tall에 10을 더해주려고 하면 오류가 발생함 -> tall이 undefined이 될 수 있기 때문임
        • 이럴 때는 '타입 가드'를 활용해 타입을 좁혀줘서 오류를 해결 해줌
          e.g) typeof tall === 'number'
  • 선택적 매개변수를 사용해야할 때 주의할 점

    • 필수 매개변수 앞에 오면 안됨
      e.g) tall?: number, age:number -> 오류 발생
    function introduce(name = '이정환', age: number tall?: number) {
      console.log(`name: ${name}`);
      if(typeof tall === 'number') {
        console.log(`tall: ${tall + 10}`);
      }
    }
    
    introduce('이정환', 27, 175);
    introduce('이정환', 27);
  • 레스트 파라미터 매개변수

    • 배열 타입을 활용해서 사용
      e.g) ...rest: number[]
      = 만약, 매개변수의 갯수를 고정하고 싶다면
      • 튜플 타입으로 만들면 됨
        e.g) ...rest: [number, number, number]
function getSum(...rest: number[]) {
  let sum = 0;
  rest.forEach((it) => (sum += it));
  return sum;
}

getSum(1, 2, 3) // 6
getSum(1, 2, 3, 4, 5) // 15

✨ 함수 타입 표현식과 호출 시그니처

  • 함수의 타입을 별도로 정의하는 방법

📍 함수 타입 표현식 (Function Type Expression)

  • 타입 별칭을 이용해 함수 타입을 별도로 정의

  • 인터넷에 돌아다니는 여러 문서나 강의에서 이 문법을 호출 시그니처 또는 함수 시그니처라고 부름

    • 그러나 타입스크립트 공식 문서에서는 이 문법 이름을 '함수 타입 표현식'이라고 소개하고 있음
  • 타입은 같지만 기능은 다른 함수들을 여러개 사용해야할때 유용함!

    type Calculate = (a: number, b: number) => number;
    
    const add: Calculate = (a, b) => a + b;
    const sub: Calculate = (a, b) => a - b;
    const multiply: Calculate = (a, b) => a * b;
    const divide: Calculate = (a, b) => a / b;
  • 함수 타입 표현식은 타입 별칭 없이도 표현식 만으로도 정의 가능!

    type Calculate = (a: number, b: number) => number;
    
    const add: (a: number, b: number) => number = (a, b) => a + b;
    const sub: Calculate = (a, b) => a - b;
    const multiply: Calculate = (a, b) => a * b;
    const divide: Calculate = (a, b) => a / b;

📍 호출 시그니처

  • 함수의 타입을 별도로 정의하는 또 다른 방법

  • 함수 타입 표현식과 동일한 기능을 함

  • 함수의 부분을 떼어내서 적은 느낌과 비슷

    • (a: number): void 만 떼낸 느낌
    function func(a: number): void {};
  • 함수의 타입을 정의하는데 중괄호{}를 열어서 마치 객체 타입을 정의하는 듯이 하는 이유는 사실 자바스크립트의 함수도 객체이기 때문!

  • 참고 자료: https://reactjs.winterlood.com/0f33b159-6b19-433b-8db4-68d6b4a122e0

    type Operation = {
      (a: number, b: number): number;
    }
    
    const add2: Operation = (a, b) => a + b;
    const sub2: Operation = (a, b) => a - b;
    const multiply2: Operation = (a, b) => a * b;
    const divide2: Operation = (a, b) => a / b;
  • 하이브리드 타입

    • 함수도 객체이기 때문에, 호출 시그니처 타입을 갖는 변수가 함수처럼 호출 될 수도 있고, 프로퍼티를 추가로 정의해 .표기법으로 객체처럼 사용할 수 있음
    • 따라서, 이 타입을 갖는 변수를 마치 객체로도 쓸 수 있고, 함수로도 쓸 수 있어서 하이브리드 타입이라고도 함
    type Operation = {
      (a: number, b: number): number;
      name: string;
    }
    
    const add2: Operation = (a, b) => a + b;
    const sub2: Operation = (a, b) => a - b;
    const multiply2: Operation = (a, b) => a * b;
    const divide2: Operation = (a, b) => a / b;
    
    add2(1, 2);
    add2.name;

✨ 함수 타입의 호환성

  • 특정 함수 타입을 다른 함수 타입으로 취급해도 괜찮은가를 판단

  • 함수 타입의 호환성을 판단하는 체크리스트

    1. 반환 값의 타입이 호환되는가
    2. 매개변수의 타입이 호환되는가
  • 이 두 가지의 기준이 모두 만족 되어야만, 함수 타입이 호환된다고 말할 수 있음

  1. 반환 값의 타입 호환

    // 기준1. 반환값이 호환되는가
    type A = () => number;
    type B = () => 10;
    
    let a: A = () => 10;
    let b: B = () => 10;
    
    a = b; // 업캐스팅
    // b = a; 오류 발생. 다운캐스팅
  • 반환 값 타입으로 보면 number 타입을 literal number 타입으로 취급하게다는 것이니 오류 발생함 (다운 캐스팅)
  1. 매개변수의 타입 호환
  • 매개변수의 개수가 같을 때

    • 반환값을 기준으로 타입의 호환성을 판단하는 것과 달리, 매개변수를 기준으로 타입의 호환성을 판단할 때는 업 캐스팅 할때는 호환이 안됨 (다운 캐스팅: 호환 O)
    // 2-1. 매개변수의 개수가 같을 때
    
    type C = (value: number) => void;
    type D = (value: 10) => void;
    
    let c: C = (value) => {}; 
    let d: D = (value) => {};
    
    // c = d; 오류 발생 (업캐스팅)
    d = c; // 다운 캐스팅
    • 왜 그럴까?
    • 매개변수가 객체 타입을 사용하는 예시를 살펴보자.
    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; // 다운캐스팅
    
    let testFunc = (animal: Animal) => {
      console.log(animal.name);
      // console.log(animal.color); 오류 발생
    }
    
    let testFunc2 = (dog: Dog) => {
      console.log(dog.name);
      console.log(dog.color);
    }
    • 함수 타입 A와 함수 타입 B를 매개변수를 기준으로 호환성을 판단할 때(반환값은 같음), B 타입을 A 타입으로 취급하려고 하면 서브타입을 슈퍼타입으로 취급하는 것이 안됨(업캐스팅 X)
      e.g) Dog 타입을 Animal 타입으로 취급 (업캐스팅) -> X
      e.g) Animal 타입을 Dog 타입으로 취급 (다운캐스팅) -> O

      • 서브타입이 가지고 있는 프로퍼티가 더 많으므로 슈퍼타입이 그 프로퍼티까지 갖고 있지 않음!!
  • 매개변수의 개수가 다를 때

    • 할당하려고 하는 쪽의 함수의 타입의 매개변수의 개수가 더 적을 때에만 호환됨 (두 함수 타입이 같은 매개변수의 타입을 가질 때임)
    // 2-2. 매개변수의 개수가 다를 때
    
    type Func1 = (a: number, b: number) => void;
    type Func2 = (a: number) => void;
    
    let func1: Func1 = (a, b) => {};
    let func2: Func2 = (a) => {};
    
    func1 = func2;
    // func2 = func1 오류. func1의 매개변수는 1개. func2의 매개변수는 2개임.

출처: 한 입 크기로 잘라먹는 타입스크립트

profile
프론트엔드개발자가 되고 싶어서 열심히 땅굴 파는 자

0개의 댓글