TypeScript 4장 - 러닝 타입스크립트(3)
포스트
취소

TypeScript 4장 - 러닝 타입스크립트(3)

TypeScript

image

Part.2

chapter.5

5.1 함수 매개변수

  • 함수의 매개변수 또한 타입을 선언할 수 있다.
  • 타입을 선언하지 않은 매개변수는 any타입으로 간주되어 무엇이든 될 수 있다.
    1
    2
    3
    4
    5
    6
    7
    
    function sing(song) {
      console.log(`Singing: ${song}`);
    }
    // 선언되지 않은 매개변수
    function sing(song: string) {
      console.log(`Singing: ${song}`);
    }
    
5.1.1 필수 매개변수
  • 타입스크립트는 함수에 선언된 모든 매개변수가 필수라고 가정한다.
  • 함수가 잘못된 수의 인수로 호출되면,타입스크립트는 타입 오류의 형태로 이의를 제기합니다.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    
    function singTwo(first: string, second: string) {
      console.log(`${first}/${second}`);
    }
    
    singTwo("Ball");
    // Error: Expected 2 arguments, but got 1.
    
    singTwo("Ball", "play"); // OK
    singTwo("Ball", "play", "friedns");
    // Error: Expected 2 arguments, but got 3.
    
5.1.2 선택적 매개변수
  • 함수 매개변수를 의도적으로 제공하지 않아 의도적으로 undefined를 사용할 수도 있다.
  • 선택적 객체 타입 속성과 유사하게 타입 애너테이션의 : 앞에 ?를 추가해 매개변수가 선택적이라고 표시한다.
  • 함수 호출에 선택적 매개변수를 제공할 필요는 없다.
  • 선택적 매개변수에는 항상undefined가 유니언 타입으로 추가되어 있다.
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    
    function Sing(song: string, singer?: string) {
      console.log(`Song ${song}`);
    
      if (singer) {
        console.log(`Singer ${singer}`);
      }
    }
    
    Sing("Any"); // OK
    Sing("Any", undefined); // OK
    Sing("Any", "Mary"); // OK
    
  • 선택적 매개변수는 암묵적으로 undefined가 될 수 있다.
  • 선택적 매개변수는 값이 undefined일지라도 항상 재공되어야 한다.

    1
    2
    3
    4
    5
    6
    7
    
    function Sing(song: string, singer: string | undefined) {
      console.log(`Song ${song} ${singer}`);
    }
    
    Sing("Any", undefined); // OK
    Sing("Any");
    // Error: Expected 2 arguments, but got 1.
    
  • 모든 선택적 매개변수는 마지막 매개변수여야 한다.
  • 필수 매개변수 전에 선택적 매개변수가 먼저 온다면 오류가 발생한다.

    1
    2
    3
    4
    5
    6
    7
    
    function Sing(song: string, singer?: string){
      ...
    } // OK
    
    function Song(song?: string, singer: string){
      ...
    }// Error: A required parameter cannot follow an optional parameter.
    
5.1.3 기본 매개변수
  • 선택적 매개변수에는 기본적으로 값이 제공되기 때문에 해당 타입스크립트 타입에는 암묵적으로 함수 내부에 | undefined 유니언 타입이 추가된다.
  • 함수의 매개변수에 대해 인수를 누락하거나 undefined 인수를 사용해서 호출하는 것을 허용한다.
  • =는 암묵적으로undefined가 추가된다.
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    
    function Sing(song: string, list = 0){
      ...
    } // list는 number|undefined
    
    Sing("Any"); // OK
    Sing("Any", 5); // OK
    Sing("Any", undefined); // OK
    Sing("Any", "1");
    // Error: Argument of type "1" is not assignable to
    // parameter of type 'number:undefined'.
    
5.1.4 나머지 매개변수
  • 자바스크립트의 일부 함수는 임의의 수의 인수로 호출할 수 있도록 만들어진다.
  • 스프레드 연산자는 함수 선언의 마지막 매개변수에 위치하고, 해당 매개변수에서 시작해 함수에 전달된 나머지 인수가 모두 단일 배열에 저장되어야 함을 나타낸다.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    
    function Sing(song: string, ...list: number[]) {
      console.log(song, list);
    }
    
    Sing("Any", 1, 2, 3, 4); // OK
    // "Any", [1,2,3,4]
    Sing("Any"); // OK
    // "Any", []
    Sing("Any", "1");
    // Error: Argument of type "string" is not assignable to parameter of
    // typer "number"
    

5.2 반환 타입

  • 함수에 다른 값을 가진 여러 개의 반환문을 포함하고 있다면, 타입스크립트는 반환 타입을 가능한 모든 반환 타입의 조합으로 유추한다.
    1
    2
    3
    4
    
    function Sing(song: string[], index: number) {
      return index < song.length ? song[index] : undefined;
    }
    // 타입: song: string[], index: number => string|undefined
    
5.2.1 명시적 반환 타입
  • 변수와 마찬가지로 타입 애너테이션을 사용해 함수의 반환 타입을 명시적으로 선언하지 않는 것이 좋다.
  • 함수에서 반환 타입을 명시적으로 선언하는 방식이 유용할 때도 종종 있다.
    • 가능한 반환값이 많은 함수가 항상 동일한 타입의 값을 반환하도록 강제한다.
    • 타입스크립트는 재귀 함수의 반환 타입을 통해 타입을 유추하는 것을 거부한다.
    • 수백 개 이상의 타입스크립트 파일이 있는 매우 큰 프로젝트에서 타입스크립트 타입 검사 속도를 높일 수 있다.
  • 함수 선언 반환 타입 애너테이션은 매개변수 목록이 끝나는 ) 다음에 배치되며, 함수 선언의 경우 {앞에 배치된다.

    1
    2
    3
    4
    5
    6
    
    function Sing(songs: string[], count = 0): number {
      return songs.length ? Sing(songs.slice(1), count + 1) : count;
    }
    // 화살표 함수의 경우
    const Sing = (songs: string[], count = 0): number =>
      songs.length ? Sing(songs.slice(1), count + 1) : count;
    
  • 함수의 반환 타입으로 할당할 수 없는 값을 반환하는 경우 타입스크립트는 할당 가능성 오류를 표시한다.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    
    function SongDate(song: string): Date | undefined {
      switch (song) {
        case "Strange Fruit":
          return new Date("April 20, 1939"); // OK
    
        case "Greensleeves":
          return "unknown";
        // Error Type "string" is not assignable to type "Date".
    
        default:
          return undefined; // OK
      }
    }
    

5.3 함수 타입

  • 함수를 값으로 전달할 수 있으며, 함수를 가지기 위한 매개변수 또는 변수의 타입을 선언하는 방법이 필요하다.
  • 함수 타입 구문은 화살표 함수와 유사하지만 함수 본문 대신 타입이 있다.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    
    let nothing: () => string;
    // 매개변수가 없고 string 타입을 반환한다.
    
    let input: (song: string[], count?: number) => number;
    // string[]매개변수와 count 선택적 매개변수 및 number 값을 반환하는 함수임을 설명한다.
    
    const songs = ["Juice", "Shake if Off", "What's up"];
    
    function runSing(getSongA: (index: number) => string {
      for(let i = 0; i < songs.length; i++){
          console.log(getSongA(i));
      }
    })
    function getSong(index: number){
      return `${songs[index]}`;
    }
    runSing(getSongA); // OK
    
    function logSong(song: string){
      return `${song}`;
    }
    
    runSing(logSong);
    // Error: Argument of type "(song: string) => string" in not
    // assignable to parameter of type "(index: number) => string".
    // Types of parameters "song" and "index" are incompatible.
    // Type "number" is not assignable to type "string".
    
    • 두 함수를 서로 할당할 수 없다는 오류를 출력할 때 타입스크립트는 일반적으로 세 가지 상세한 단계를 제공한다.
    • runSing에 대한 오류 메시지는 다음과 같은 내용을 담고 있다.
      • 첫 번째 들여쓰기 단계는 두 함수 타입을 출력한다.
      • 다음 들여쓰기 단계는 일치하지 않는 부분을 지정한다.
      • 마지막 들여쓰기 단계는 일치하지 않는 부분에 대한 정확한 할당 가능성 오류를 출력한다.
    • 단계별로 제공하는 내용은 다음과 같다.
      • logSong: (song: string) => string은 getSongA: (index: number) => string에 할당되도록 제공된 타입이다.
      • logSong의 song 매개변수는 getSongA의 index 매개변수로 할당됩니다.
      • song의 string 타입은 index의 number타입에 할당할 수 없다.
5.3.1 함수 타입 괄호
  • 함수 타입은 다른 타입이 사용되는 모든 곳에 배치할 수 있다.
  • 유니언 타입도 포함된다.
  • 유니언 타입의 애너테이션에서 함수 반환 위치를 나타내거나 유니언 타입을 감싸는 부분을 표시할 때 괄호를 사용한다.
    1
    2
    3
    4
    
    let returnString: () => string | undefined;
    // 타입은 stirng | undefined 유니언을 반환하는 함수이다.
    let maybeReturnString: () => string | undefined;
    // 타입은 undefined나 string을 반환하는 함수이다.
    
5.3.2 매개변수 타입 추론
  • 타입스크립트는 선언된 타입의 위치에 제공된 함수의 매개변수 타입을 유추할 수 있다.

    1
    2
    3
    4
    5
    6
    
    let singer: (song: string) => string;
    
    singer = function (song) {
      return `Singing: ${song.toUpperCase()}`; // OK
      // song: string 타입
    };
    
  • 함수를 매개변수로 갖는 함수에 인수로 전달된 함수는 해당 매개변수 타입도 유추할 수 있다.

    1
    2
    3
    4
    5
    
    const songs = ["Call me", "Jolene", "The Chain"];
    
    songs.forEach((song, index) => {
      console.log(`${song} is at index ${index}`);
    });
    
5.3.3 함수 타입 별칭
  • 함수 타입에서도 타입 별칭을 사용할 수 있다.
  • string 타입을 매개변수로 받고, number 타입으로 반환하는 함수의 예시

    1
    2
    3
    4
    5
    6
    7
    8
    
    type StringToNumber = (input: string) => number;
    
    let stringToNumber: StringToNumber;
    
    stringToNumber = (input) => input.length; // OK
    
    stringToNumber = (input) => input.toUpperCase();
    // Error: Type 'string' is not assignable to type 'number'.
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    
    type NumberToString = (input: number) => string;
    
    function usesNumberToString(numberToString: NumberToString) {
      console.log(`The string is: ${numberToString(1234)}`);
    }
    
    userNumberToString((input) => `${input}! Hooray!`); // OK
    
    userNumberToString((input) => input * 2);
    // Error: Type 'number' is not assignable to type 'string'.
    

5.4 그 외 반환 타입

5.4.1 void 반환 타입
  • return 문이 없는 함수이거나 값을 반환하지 않는 return 문을 가진 함수는 어떤 값도 반환하지 않는다.
  • 타입스크립트는 void 키워드를 사용해 반환 값이 없는 함수의 반환 타입을 확인할 수 있다.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    
    function logSong(song: string | undefined): void {
      if (!song) {
        return; // OK
      }
    
      console.log(`${song}`);
    
      return true;
      // Error: Type 'boolean' is not assignable to type 'void'.
    }
    
  • 함수 타입 선언 시 void 반환 타입은 매우 유용하다.
  • 함수 타입을 선언할 때 void를 사용하면 함수에서 반환되는 모든 값은 무시된다.

    1
    2
    3
    4
    5
    6
    
    let songLogger: (song: string) => void;
    songLogger = (song) => {
      console.log(`${songs}`);
    };
    
    songLogger("Heart of Glass"); // OK
    
  • 자바스크립트 함수는 실젯값이 반환되지 않으면 기본으로 모두 undefined를 반환하지만 void 는 undefined 와 동일하지 않다.
  • void는 함수의 반환 타입이 무시된다는 것을 의미하고 undefined 는 반환되는 리터럴 값이다.

    1
    2
    3
    4
    5
    6
    7
    8
    
    function returnsVoid() {
      return;
    }
    
    let lazyValue: string | undefined;
    
    lazyValue = returnsVoid();
    // Error: Type 'void' is not assignable to type 'string|undefined'.
    
  • undefined 와 void 를 구분해서 사용하면 매우 유용하다.
  • void 를 반환하도록 선언된 타입 위치에 전달된 함수가 반환된 모든 값을 무시하도록 설정할 때 유용하다.
  • forEach 에 제공되는 함수는 원하는 모든 값을 반환할 수 있다.
  • void 타입은 자바스크립트가 아닌 함수의 반환 타입을 선언하는 데 사용하는 타입스크립트 키워드이며, 함수의 반환값이 자체적으로 반환될 수 있는 값도 아니고, 사용하기 위한 것도 아니다.

    1
    2
    3
    4
    5
    6
    7
    
    const records: string[] = [];
    
    function saveRecords(newRecords: string[]) {
      newRecords.forEach((record) => records.push(record));
    }
    
    saveRecords(["21", "Come on Over", "The Bodyguard"]);
    
5.4.2 never 반환 타입
  • 일부 함수는 값을 반환하지 않으며, never 반환 함수는 의도적으로 항상 오류를 발생시키거나 무한 루프를 실행하는 함수이다.
  • 함수가 절대 반환하지 않도록 의도하려면 명시적 : never 타입 애너테이션을 추가해 해당 함수를 호출한 후 모든 코드가 실행되지 않음을 나타낸다.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    
    function fail(message: string): never {
      throw new Error(`Invariant failure: ${message}.`);
    }
    
    function workWithUnsafeParam(param: unknown) {
      if (typeof param !== "string") {
        fail(`param should be a string, not ${typeof param}`);
      }
    
      param.toUpperCase(); // OK
    }
    

5.5 함수 오버로드

  • 선택적 매개변수와 나머지 매개변수만으로 표현할 수 없는 매우 다른 매개변수들로 호출될 수 있으며, 이러한 함수를 오버로드 시그니처라고 부르는다.
  • 하나의 최종 구현 시그니처와 그 함수의 본문 앞에 서로 다른 버전의 함수 이름, 매개변수, 반환 타입을 여러 번 선언한다.
  • 함수 오버로드는 복잡하고 설명하기 어려운 함수 타입에 사용하는 최후의 수단이기 때문에 가능하면 함수 오버로드를 사용하지 않는 것이 좋다.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    
    function createDate(timestamp: number): Date;
    function createDate(month: number, day: number, year: nmumber): Date;
    function createDate(monthOrTimestamp: number, day?: number, year?: nmumber) {
      return day === undefined || year === undefined
        ? new Date(monthOrTimestamp)
        : new Date(year, monthOrTimestamp, day);
    }
    
    createDate(554356800); // OK
    createDate(7, 27, 1987); // OK
    
    createDate(4, 1);
    // Error: No overload expects 2 arguments, but overloads
    // do exist that expect either 1 or 3 arguments.
    
    • createDate 함수는 1개의 timestamp 매개변수 또는 3개의 매개변수 (month, day, year)를 사용해 호출한다.
    • 허용된 수의 인수를 사용해 호출할 수 있지만 2개의 인수를 사용해 호출하면 2개의 인수를 허용하는 오버로드 시그니처가 없기 떄문에 타입 오류가 발생한다.
5.5.1 호출 시그니처 호환성
  • 오버로드된 함수의 구현에서 사용되는 구현 시그니처는 매개변수 타입과 반환 타입에 사용하는 것과 동일하다.
  • 함수의 오버로드 시그니처에 있는 함수 타입과 각 매개변수는 구현 시그니처에 있는 동일한 인덱스의 매개변수에 할당할 수 있어야 한다.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    
    function format(data: string): string; // OK
    function format(data: string, neadle: string, haystack: string): string; // OK
    
    function format(getData: () => string): string;
    // Error: This overload signature is not compatible with its implementation signature.
    
    function format(data: string, needle?: string, haystack?: string) {
      return needle && haystack ? data.replace(needle, haystack) : data;
    }
    
    • format 함수의 시그니처는 첫 번째 매개변수를 string으로 선언한다.
    • 두 개의 오버로드 시그니처는 string 타입과 호환되지만, 세 번째 오버로드 시그니처의 () => string 타입과는 호환되지 않는다.

5.6 마치며

  • 타입 애너테이션으로 함수 매개변수 타입을 선언할 수 있다.
  • 타입 시스템의 동작을 변경하기 위한 선택적 매개변수, 기본 매개변수, 나머지 매개변수를 선언한다.
  • 타입 애너테이션으로 함수 반환 타입을 선언할 수 있다.
  • void 타입으로 사용 가능한 값을 반환하지 않는 함수를 알아낼 수 있다.
  • never 타입으로 절대 반환하지 않는 함수를 알아낼 수 있다.
  • 함수 오버로드를 사용해서 다양한 함수 호출 시그니처를 실행할 수 있다.
이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.