[typescript] ch04 함수

ch04

함수

4.1. 함수 선언과 호출

기본 함수 예시

  • 보통 실무에서는 반환 타입은 자동으로 추론되도록 함(리턴 타입을 명시 하지 않는 경우가 많음)
function add(a: number, b: number): number {
  return a + b;
}

함수 선언 예시

// 이름을 붙인 함수
function greet(name: string) {
  return "hello" + name;
}

// 함수 표현식
let greet = function (name: string) {
  return "hello" + name;
};

// 화살표 함수 표현식
let greet = (name: string) => {
  return "hello" + name;
};

// 화살표 함수 축약식
let greet = (name: string) => "hello" + name;

// 함수 생성자 - 사용하지 않는 것이 좋음
let greet = new Function("name", 'return "hello" + name');

용어 설명

  • 매개변수(parameter) - 함수 선언의 일부이며 함수를 실행하는 데 필요한 데이터 조각 (정형 매개변수)
  • 인수(argument) - 함수를 호출 할 때 전달해야 하는 데이터 조각 (실질 매개변수)

4.1.1. 선택적 매개변수와 기본 매개변수

? 를 이용하여 선택적 매개 변수를 사용할 수 있음

function log(message: string, userId?: string) {
  let time = new Date().toLocalTimeString();
  console.log(time, message, userId || "not signed in");
}

// 기본값을 지정할 수 있음. 데이터 타입은 자동으로 추론됨.
function log(message: string, userId = "not signed in") {
  let time = new Date().toLocalTimeString();
  console.log(time, message, userId);
}

타입에서 선택형 마크 ? 사용

  • 보통 실무에서는 선택적 매개변수 보단 기본 매개변수를 사용하게 됨
type Context = {
  appId?: string;
  userId?: string;
};

참조 : call(열거형), apply (배열형)

this 를 전달하여 해당 함수 호출

참조 : bind

this 를 전달하여 새로운 함수를 생성

let person1 = {
  name: "Jo",
};

let person2 = {
  name: "Kim",
  study: function () {
    console.log(this.name + "이/가 공부를 하고 있습니다.");
  },
};

person2.study(); // Kim이/가 공부를 하고 있습니다.

// bind()
let student = person2.study.bind(person1);

student(); // Jo이/가 공부를 하고 있습니다.

console.log(person1); // { name: 'Jo' }
console.log(person2); // { name: 'Kim', study: [Function: study] }
console.log(student); // [Function: bound study]

arguments

  • 함수에 전달된 인수에 해당하는 Array 형태의 객체
  • 유사배열은 보통의 배열과 형태는 같지만, 배열이 아니기 때문에 Array.prototype.join() 등의 배열의 메소드를 사용할 수 없다
function foo(a, b, c) {
  console.log(arguments);
}

foo(1, 2, 3); // [Arguments] { '0': 1, '1': 2, '2': 3 }

4.1.4 this 의 타입

  • 보통 클래스 메소드를 제외한 다른 모든 곳에서 this 사용을 금한다
  • this의 타입을 보장하지 않기 때문 (이를 위해 명시적으로 지정 가능)
function fancyDate(this: Date) {
  return `${this.getDate()} / ${this.getMonth()} / ${this.getYear()}`;
}

4.1.5. generator

  • 함수명 앞에 붙은 별표(*)는 이 함수가 제너레이터 임을 의미
  • 제너레이터를 호출하면 이터러블 반복자가(IterableIterator) 반환
  • 제너레이터는 영구적으로 값을 생성할 수 있음
  • 제너레이터는 yield 라는 키워드로 값을 방출
  • 소비자가 다음 값을 다시 요청하기 전 까지는 실행을 중지
  • while(true) 루프가 영원히 실행되다가 비정상 종료되는 현상이 발생되지 않음.
// 제너레이터
function* createNumbers(): IterableIterator<number> {
  let n = 0;
  while (n < 10) {
    yield n++;
  }
  return 100;
}

let numbers = createNumbers();
console.log(numbers.next()); // { value: 0, done: false }
console.log(numbers.next()); // { value: 1, done: false }
console.log(numbers.next()); // { value: 2, done: false }
console.log(numbers.next()); // { value: 3, done: false }
console.log(numbers.next()); // { value: 4, done: false }
console.log(numbers.next()); // { value: 5, done: false }
console.log(numbers.next()); // { value: 6, done: false }
console.log(numbers.next()); // { value: 7, done: false }
console.log(numbers.next()); // { value: 8, done: false }
console.log(numbers.next()); // { value: 9, done: false }
console.log(numbers.next()); // { value: 100, done: true }
console.log(numbers.next()); // { value: undefined, done: true }

4.1.6. 반복자

  • 이터러블(iterable) : Symbol.iterator 라는 프로퍼티(반복자를 반환하는 함수)를 가진 모든 객체
  • 반복자(iterator) : next 라는 매소드(value, done 두 프로퍼티를 가진 객체를 반환)를 정의한 객체

https://runebook.dev/ko/docs/typescript/iterators-and-generators

  • Symbol.iterator 속성에 대한 구현이있는 객체는 반복 가능한 것으로 간주 됩니다.
  • Array , Map , Set , String , Int32Array , Uint32Array 등과 같은 일부 내장 유형 에는 이미 Symbol.iterator 속성이 구현되어 있습니다.
  • 객체의 Symbol.iterator 함수는 반복 할 값 목록을 반환합니다.

Iterable interface

Iterable 은 위에 나열된 반복 가능한 유형을 사용하려는 경우 사용할 수있는 유형입니다. 다음은 예입니다.

function toArray<X>(xs: Iterable<X>): X[] {
  return [...xs];
}

for-of, for-in

let list = [4, 5, 6];

for (let i in list) {
  // 키 반환
  console.log(i); // "0", "1", "2",
}

for (let i of list) {
  // 값 반환
  console.log(i); // 4, 5, 6
}

참조 : TypeScript :: 6. 반복기와 재생기

// 문자형 반복자 생성
// Iterable 을 구현해야 됨
class StringIterable implements Iterable<string> {
  #strings: string[];
  #currentIndex: number = 0;
  constructor(strings: string[]) {
    this.#strings = strings;
  }

  [Symbol.iterator](): Iterator<string> {
    let that = this;
    let currentIndex = that.#currentIndex,
      length = that.#strings.length;

    const iterator: Iterator<string> = {
      next(): { value: string; done: boolean } {
        const value = that.#strings[currentIndex];
        const done = currentIndex == length;
        currentIndex++;
        return { value, done };
      },
    };
    return iterator;
  }
}

for (let value of new StringIterable(["hello", "world", "!"]))
  console.log(value);

4.1.7. 호출 시그니처

  • 함수 표현식 log 를 선언하면서 Log 타입임을 명시
  • 매개변수, 반환타입 등은 사전에 지정 했기 때문에 별도 명시하지 않아도 됨. (c의 header(.h) 느낌)
type Log = (message: string, userId?: string) => void;

let log: Log = (message, userId = "not signed in") => {
  let time = new Date().toISOString();
  console.log(time, message, userId);
};
log("wow");

4.1.8. 문맥적 타입화

  • times 를 호출할 때 함수 선언을 인라인으로 제공하면 인수로 전달하는 함수의 타입을 명시할 필요가 없다.
function times(f: (index: number) => void, n: number) {
  for (let i = 0; i < n; i++) f(i);
}
times((n) => console.log(n), 4);

// function times(f: Function, n: number) {
// 위와 같이 함수를 지정해도 동작은 가능
// 하지만 함수의 형태를 지정하지 않아 warning 을 보여줌
// 'n' 매개 변수는 암시적으로 'any' 형식이지만, 사용량에서 더 나은 형식을 유추할 수 있습니다.ts(7044)

4.1.9. 오버로드 된 함수 타입

아래는 동일 함. 단축형 시그니처를 사용하는 것을 추천. 물론 복잡한 상황에서는 아래 것이 유용

// 단축형 호출 시그니처
type Log = (message: string, userId?: string) => void;

// 전체 호출 시그니처
type Log = {
  (message: string, userId?: string): void;
};
  • 타입스크립트는 선언한 순서대로 오버로드 수행
  • 타입스크립트에서는 오버로드 된 함수 선언으로 제공하고, 입력 타입에 따라 달라지는 함수의 출력 타입은 정적 타입 시스템으로 각각 제공
  • 오버로드를 사용할 때는 함수를 쉽게 구현할 수 있도록 가능한 한 구현의 시그니처를 특장하는 것이 좋다.
  • 타입을 좁게(구체적으로) 유지하는 것이 어떻게 주어진 시그니처로 함수를 구현하는 데 도움을 줄까 생각 함이 좋음
type Reservation = { from: Date; to: Date; destination: string };

// 2가지 시그니처를 가지고 있음
type Reserve = {
  (from: Date, to: Date, destination: string): Reservation;
  (from: Date, destination: string): Reservation;
};

// 위에서 정의한 시그니처와 리턴 타입을 맞춰 주도록 한다
let r1: Reserve = (
  from: Date,
  toOrDestination: Date | string,
  destination?: string
) => {
  if (toOrDestination instanceof Date) {
    return { from, to: toOrDestination, destination: destination || "" };
  } else {
    return { from, to: from, destination: destination || "" };
  }
};

오버로드는 자연스럽게 브라우저 DOM API 에서 유용하게 활용됨

  • <a> 요소에 대응하는 HTMLAnchorElement
  • <canvas> 요소에 대응하는 HTMLCanvasElement
  • <table> 요소에 대응하는 HTMLTableElement
Sort:  

[광고] STEEM 개발자 커뮤니티에 참여 하시면, 다양한 혜택을 받을 수 있습니다.

@wonsama transfered 2 KRWP to @krwp.burn. voting percent : 87.35%, voting power : 15.47%, steem power : 1986237.39, STU KRW : 1200.
@wonsama staking status : 1793.429 KRWP
@wonsama limit for KRWP voting service : 1.793 KRWP (rate : 0.001)
What you sent : 2 KRWP
Refund balance : 0.207 KRWP [65073847 - cbb4360cc79e95bc8ab281e4a206793faa638544]

Upvoted! Thank you for supporting witness @jswit.
default.jpg

Coin Marketplace

STEEM 0.18
TRX 0.16
JST 0.031
BTC 63223.35
ETH 2688.72
USDT 1.00
SBD 2.55