사용자 도구

사이트 도구


typescript:function

Functions

Introduction

JavaScript의 Function은 application의 기초적인 block을 만든다. 이 것을 통해서 abstraction, mimicking classes, information hiding, 그리고 modules의 layers를 만들게 하여 준다. TypeScript는 이러한 것들을 쉽게 만들도록 표준 JavaScript function에 새로운 능력을 추가한다.

Functions

시작하기, JavaScript에서와 마찬가지로, TypeScript functions는 명명 function 또는 익명 function으로 만들 수 있습니다. 이를 통해 API에서 함수 목록을 작성하든 다른 기능으로 이전 할 것인지에 관계없이 응용프로그램에 가장 적합한 방법을 선택할 수 있습니다.

JavaScript에서 이러한 두 가지 접근방식을 빠르게 요약하면 다음과 같습니다.

// Named function
function add(x, y) {
    return x + y;
}
 
// Anonymous function
let myAdd = function(x, y) { return x + y; };;

JavaScript와 마찬가지로 함수는 함수 본문 외부의 변수를 참조 할 수 있습니다. 그들은 그렇게 할 때 이러한 변수를 포착(capture)한다고 합니다. 이것이 어떻게 작동하는지 (그리고이 기술을 사용할 때의 절충)는 이 기사의 범위를 벗어나는 것이지만,이 메커니즘이 어떻게 작동 하는지를 이해하면 JavaScript 및 TypeScript를 사용하여 작업하는 것이 중요합니다.

let z = 100;
function addToZ(x, y) {
  return x + y + z;
}

Function Types

Typing the function

이전 단순한 예제에 타입을 추가해보자

function add(x: number, y: number): number {
  return x + y;
}
let myAdd = function(x: number, y: number): number { return x + y; };

매개변수 각각의 타입과 그리고 함수 자체의 반환 타입을 추가 할 수 있다.TypeScript는 return 문을 보고 리턴 유형을 파악할 수 있으므로 많은 경우에 선택적으로 남겨 둘 수 있습니다.

Writing the function type

이제는 함수를 타이프했습니다. 함수 타입의 각 부분을 살펴봄으로써 함수의 전체 유형을 작성해 봅시다.

let myAdd: (x: number, y: number) => numbe =
    function(x: number, y: number): number { return x + y; };

함수의 형식은 인수의 형식과 반환 형식의 두 부분이 동일합니다. 전체 함수 유형을 작성할 때 두 부분이 필요합니다. 매개 변수 유형을 매개 변수 목록과 같이 작성하여 각 매개 변수에 이름과 유형을 지정합니다. 이 이름은 가독성을 돕기위한 것입니다. 대신에 다음과 같이 쓸 수 있습니다.

let myAdd: (baseValue: number, increment: number) => number =
    function(x: number, y: number): number { return x + y; };

매개 변수 유형이 정렬되어있는 한, 함수 유형에 매개 변수를 지정하는 이름에 관계없이 함수의 유효한 유형으로 간주됩니다.

두 번째 부분은 반환 유형입니다. 매개 변수와 반환 유형 사이에 굵은 화살표 (⇒)를 사용하여 반환 유형을 명확하게합니다. 앞에서 언급했듯이 이것은 함수 유형에서 필수적인 부분이므로 함수가 값을 반환하지 않으면 이것를 끄는 대신에 void를 사용합니다.

매개변수와 반환유형만 함수 유형을 구성합니다. 캡처된 변수는 유형에 반영되지 않습니다. 실제로 캡처된 변수는 함수의 “숨겨진 상태”의 일부이며 해당 API를 구성하지 않습니다.

Inferring the types

이 예제를 가지고 노는 경우 TypeScript 컴파일러는 방정식의 한쪽에만 형식이 있어도 형식을 알아낼 수 있습니다.

// myAdd has the full function type
let myAdd = function(x: number, y: number): number { return x + y; };
 
// The parameters 'x' and 'y' have the type number
let myAdd: (baseValue: number, increment: number) => number =
    function(x, y) { return x + y; };

이를 유형 추론의 한 형태 인 “contextual typing”이라고합니다. 이렇게하면 프로그램을 계속 입력하기 위한 노력을 줄일 수 있습니다.

Optional and Default Parameters

TypeScript에서, 모든 파라메터는 함수에 필요하다고 가정합니다. 이것은 null 또는 undefined가 주어질 수 없다는 것을 의미하는 것이 아니라, 함수가 호출 될 때 컴파일러는 사용자가 각 매개변수에 값을 제공했는지 확인합니다. 컴파일러는 사용자가 각 매개변수에 값을 제공했는지 확인합니다. 컴파일러는 또한 이 매개변수가 함수로 전달되는 유일한 매개변수라고 가정합니다. 즉, 함수에 주어진 인수의 수는 함수가 예상하는 매개변수의 수와 일치해야 합니다.

function buildName(firstName: string, lastName: string) {
    return firstName + " " + lastName;
}
 
let result1 = buildName("Bob");                  // error, too few parameters
let result2 = buildName("Bob", "Adams", "Sr.");  // error, too many parameters
let result3 = buildName("Bob", "Adams");         // ah, just right

자바 스크립트에서 모든 매개 변수는 선택 사항이며 사용자는 적합하다고 판단되는 매개 변수를 그대로 둘 수 있습니다. 그들이 할 때, 그들의 값은 undefined입니다. 우리는 TypeScript에서 매개 변수의 끝에 ?를 추가하여 선택적 파라메터로 선언합니다. 예를 들어 위의 lastName 매개변수를 선택적으로 사용하고자한다고 가정 해 보겠습니다.

function buildName(firstName: string, lastName?: string) {
  if (lastName)
    return firstName + " " + lastName;
  else
    return firstName;
}
 
let result1 = buildName("Bob");                  // works correctly now
let result2 = buildName("Bob", "Adams", "Sr.");  // error, too many parameters
let result3 = buildName("Bob", "Adams");         // ah, just right

선택적 매개변수는 필수 매개변수에 뒤에 따라야 합니다. lastName보다 firstName을 선택적으로 만들고 싶으면 함수의 매개변수 순서를 변경해야하며 목록에서 firstName을 마지막에 넣어야 합니다.

TypeScript에서 사용자가 매개 변수를 제공하지 않거나 사용자가 그 자리에 undefined를 전달하면 매개 변수가 할당되는 값을 설정할 수도 있습니다. 이를 기본 초기화 매개 변수라고합니다. 앞의 예제를 취하고 성을 기본값으로 “Smith”로 설정합시다.

function buildName(firstName: string, lastName = "Smith") {
    return firstName + " " + lastName;
}
 
let result1 = buildName("Bob");                  // works correctly now, returns "Bob Smith"
let result2 = buildName("Bob", undefined);       // still works, also returns "Bob Smith"
let result3 = buildName("Bob", "Adams", "Sr.");  // error, too many parameters
let result4 = buildName("Bob", "Adams");         // ah, just right

모든 필수 매개 변수 다음에 오는 기본 초기화 매개 변수는 선택적 매개 변수처럼 취급되며 선택적 매개 변수와 마찬가지로 해당 함수를 호출 할 때 생략 할 수 있습니다. 이는 선택적 매개 변수를 의미하며 후행 기본 매개 변수는 해당 유형에서 공통성을 공유하므로 둘 다

function buildName(firstName: string, lastName?: string) {
    // ...
}
function buildName(firstName: string, lastName = "Smith") {
    // ...
}
function buildName(firstName = "Will", lastName: string) {
    return firstName + " " + lastName;
}

Rest Parameters

필수 매개 변수, 선택적 매개 변수 및 디폴드 매개 변수는 모두 한 가지 공통점이 있습니다. 한 번에 하나의 매개 변수에 대해 설명합니다. 때로는 여러 매개 변수를 그룹으로 사용하거나 함수가 궁극적으로 취할 매개 변수의 수를 모를 수 있습니다. JavaScript에서는 모든 함수 본문에서 볼 수있는 arguments 변수를 사용하여 인수를 직접 사용할 수 있습니다.

TypeScript에서는 다음 인수를 함께 변수로 수집 할 수 있습니다.

function buildName(firstName: string, ...restOfName: string[]) {
    return firstName + " " + restOfName.join(" ");
}
 
// employeeName will be "Joseph Samuel Lucas MacKinzie"
let employeeName = buildName("Joseph", "Samuel", "Lucas", "MacKinzie");

나머지 매개 변수는 무한한 수의 선택적 매개 변수로 처리됩니다. rest 매개 변수에 인수를 전달할 때 원하는 만큼 사용할 수 있습니다. 너는 아무도 지나칠 수 없다. 컴파일러는 ellipsis[줄임표] () 다음에 주어진 이름으로 전달 된 인수 배열을 작성하여 함수에서 사용할 수 있도록합니다.

줄임표는 나머지 매개 변수가 있는 함수의 유형에도 사용됩니다.

function buildName(firstName: string, ...restOfName: string[]) {
    return firstName + " " + restOfName.join(" ");
}
 
let buildNameFun: (fname: string, ...rest: string[]) => string = buildName;

this

JavaScript에서 this를 사용하는 방법을 배우는 것은 통과 의례의 일입니다. TypeScript는 JavaScript의 상위 집합이므로 TypeScript 개발자는 이 메서드를 사용하는 방법과 올바르게 사용되지 않는 시점을 찾는 방법을 배워야합니다. 다행스럽게도 TypeScript를 사용하면 두 가지 기술을 사용하여 잘못된 용도를 잡을 수 있습니다. 그러나 이것이 JavaScript에서 어떻게 작동하는지 알아야 할 필요가 있다면 Yehuda Katz의 Understanding JavaScript Function Invocation과 "this"를 먼저 읽으십시오. 예후다(Yehuda)의 기사는이 내부 동작에 대해 설명합니다. 여기서는 기본 사항 만 다루겠습니다.

this and arrow functions

JavaScript에서 this는 함수가 호출 될 때 설정된 변수입니다. 이것은 매우 강력하고 유연한 기능이지만 항상 함수가 실행되는 문맥에 대해 알 필요가 있습니다. 특히 함수를 반환하거나 인수를 함수로 전달할 때 이것은 혼란스럽습니다.

예제를 살펴 보겠습니다:

let deck = {
    suits: ["hearts", "spades", "clubs", "diamonds"],
    cards: Array(52),
    createCardPicker: function() {
        return function() {
            let pickedCard = Math.floor(Math.random() * 52);
            let pickedSuit = Math.floor(pickedCard / 13);
 
            return {suit: this.suits[pickedSuit], card: pickedCard % 13};
        }
    }
}
 
let cardPicker = deck.createCardPicker();
let pickedCard = cardPicker();
 
alert("card: " + pickedCard.card + " of " + pickedCard.suit);

createCardPicker는 그 자체로 함수를 반환하는 함수입니다. 예제를 실행하려고하면 예상되는 경고 상자 대신 오류가 발생합니다. 이것은 createCardPicker에 의해 생성된 함수에서 사용되는 this가 deck 객체 대신 window로 설정되기 때문입니다. 그 이유는 우리가 cardPicker()를 단독 호출하기 때문입니다. 이와 같은 최상위 비메소드 구문 호출은 window를 사용합니다. (참고 : strict mode하에서 thiswindow가 아니라 undefined이다.)

나중에 사용할 함수를 반환하기 전에 함수가 this가 올바른지 확인하여 이 문제를 해결할 수 있습니다. 이렇게하면 나중에 사용되는 방법에 관계없이 원래의 deck객체를 계속 볼 수 있습니다. 이를 위해 함수 표현식을 ECMAScript 6 화살표 구문을 사용하도록 변경합니다. 화살표 함수는 호출 된 곳이 아닌 함수가 생성 된 곳을 캡처합니다.

let deck = {
    suits: ["hearts", "spades", "clubs", "diamonds"],
    cards: Array(52),
    createCardPicker: function() {
        // NOTE: the line below is now an arrow function, allowing us to capture 'this' right here
        return () => {
            let pickedCard = Math.floor(Math.random() * 52);
            let pickedSuit = Math.floor(pickedCard / 13);
 
            return {suit: this.suits[pickedSuit], card: pickedCard % 13};
        }
    }
}
 
let cardPicker = deck.createCardPicker();
let pickedCard = cardPicker();
 
alert("card: " + pickedCard.card + " of " + pickedCard.suit);

더 좋게도, 컴파일러에 –noImplicitThis 플래그를 전달하면이 실수를 할 때 TypeScript가 경고합니다. this.suits [pickedSuit]의 this는 any 유형입니다.

this parameters

불행히도 this.suits [pickedSuit]의 유형은 여전히 any입니다. 이는 객체 리터럴 내부의 함수 표현식에서 비롯 되었기 때문입니다. 이 문제를 해결하려면이 매개 변수를 명시적으로 제공 할 수 있습니다. 이 매개 변수는 함수의 매개 변수 목록에서 처음 나오는 가짜 매개 변수입니다.

function f(this: void) {
    // make sure `this` is unusable in this standalone function
}

위의 예인 Card와 Deck에 몇 가지 인터페이스를 추가하여 유형을 명확하고 쉽게 재사용 할 수 있게 하십시오.

interface Card {
    suit: string;
    card: number;
}
interface Deck {
    suits: string[];
    cards: number[];
    createCardPicker(this: Deck): () => Card;
}
let deck: Deck = {
    suits: ["hearts", "spades", "clubs", "diamonds"],
    cards: Array(52),
    // NOTE: The function now explicitly specifies that its callee must be of type Deck
    createCardPicker: function(this: Deck) {
        return () => {
            let pickedCard = Math.floor(Math.random() * 52);
            let pickedSuit = Math.floor(pickedCard / 13);
 
            return {suit: this.suits[pickedSuit], card: pickedCard % 13};
        }
    }
}
 
let cardPicker = deck.createCardPicker();
let pickedCard = cardPicker();
 
alert("card: " + pickedCard.card + " of " + pickedCard.suit);

이제 TypeScript는 createCardPicker가 Deck 객체에서 호출 될 것으로 예상합니다. 즉, 이것은 Deck 형식이므로 아무 것도 아니므로 –noImplicitThis는 오류를 발생시키지 않습니다.

this parameters in callbacks

나중에 콜백 할 라이브러리에 함수를 전달할 때 콜백에서 this 오류를 실행할 수도 있습니다. 콜백을 호출하는 라이브러리는 일반 함수처럼 호출하기 때문에 thisundefined일 것입니다. 일부 작업에서는 this 매개 변수를 사용하여 콜백으로 인한 오류를 방지 할 수 있습니다. 먼저, 라이브러리 제작자는 다음과 같이 this를 갖는 콜백 유형에 주석을 달아야합니다.

interface UIElement {
  addClickListener(onclick: (this: void, e: Event) => void): void;
}

this: voidaddClickListeneronclickthis 유형을 필요로하지 않는 함수가 될 것으로 예상 함을 의미합니다. 둘째, this를 갖는 호출 코드에 주석을 달아라.

class Handler {
  info: string;
  onClickBad(this: Handler, e: Event) {
    // oops, used `this` here. using this callback would crash at runtime
    this.info = e.message;
  }
}
let h = new Handler();
uiElement.addClickListener(h.onClickBad); // error!

this 주석을 사용하면 처리기의 인스턴스에서 onClickBad를 호출해야한다는 사실을 명시하게됩니다. 그런 다음 TypeScript는 addClickListener에 this: void가 있는 함수가 필요하다는 것을 감지합니다. 오류를 수정하려면 다음 유형을 변경하십시오.

class Handler {
  info: string;
  onClickGood(this: void, e: Event) {
    // can't use `this` here because it's of type void!
    console.log('clicked!');
  }
}
let h = new Handler();
uiElement.addClickListener(h.onClickGood);

onClickGood는이 유형을 this: void로 지정하기 때문에 addClickListener에 전달할 수 있습니다. 물론 이것은 this.info를 사용할 수 없다는 것을 의미합니다. 둘 다 원한다면 화살표 함수를 사용해야합니다.

class Handler {
    info: string;
    onClickGood = (e: Event) => { this.info = e.message }
}

이것은 화살표 함수가 this를 사용하기 때문에 작동합니다. 그래서 당신은 항상 이것을 기대하는 무언가에 전달할 수 있습니다 this: void. 단점은 처리기 유형의 객체 당 하나의 화살표 함수가 작성된다는 것입니다. 한편, 메소드는 한 번만 작성되어 Handler의 프로토 타입에 첨부됩니다. 핸들러 유형의 모든 객체간에 공유됩니다.

Overloads

let suits = ["hearts", "spades", "clubs", "diamonds"];
 
function pickCard(x: {suit: string; card: number; }[]): number;
function pickCard(x: number): {suit: string; card: number; };
function pickCard(x): any {
    // Check to see if we're working with an object/array
    // if so, they gave us the deck and we'll pick the card
    if (typeof x == "object") {
        let pickedCard = Math.floor(Math.random() * x.length);
        return pickedCard;
    }
    // Otherwise just let them pick the card
    else if (typeof x == "number") {
        let pickedSuit = Math.floor(x / 13);
        return { suit: suits[pickedSuit], card: x % 13 };
    }
}
 
let myDeck = [{ suit: "diamonds", card: 2 }, { suit: "spades", card: 10 }, { suit: "hearts", card: 4 }];
let pickedCard1 = myDeck[pickCard(myDeck)];
alert("card: " + pickedCard1.card + " of " + pickedCard1.suit);
 
let pickedCard2 = pickCard(15);
alert("card: " + pickedCard2.card + " of " + pickedCard2.suit);

컴파일러가 올바른 유형 검사를 선택하기 위해 기본 JavaScript와 비슷한 과정을 거칩니다. 오버로드 목록을보고 첫 번째 오버로드로 진행하여 제공된 매개 변수를 사용하여 함수를 호출합니다. 일치하는 것을 찾으면,이 과부하를 올바른 과부하로 선택합니다. 이러한 이유 때문에 가장 구체적인 상세에서 거의 구체적인 상세까지 오버로드 순서로하는 것이 일반적입니다.

pickCard(x) 함수는 모든 객체가 오버로드리스트의 일부가 아니므로 객체를 취하는 오버로드와 숫자를 취하는 오버로드의 두 가지 오버로드 만 있습니다. 다른 매개 변수 유형으로 pickCard를 호출하면 오류가 발생합니다.

예제

function add(a: string, b: string): string;
function add(a: number, b: number): string;
function add(a, b): any {
  return a + b;
}

함수명과 매개변수의 개수는 같지만 타입을 다른 경우. 다른 언어의 오버로드는 함수명만 동일하면 되지만 TypeScript의 오버로딩은 함수명과 매개변수의 갯수가 같아야 한다.

typescript/function.txt · 마지막으로 수정됨: 2025/04/15 10:05 저자 127.0.0.1