[typescript] ch04 함수

in SteemCoinPan •  2 months ago 

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
Authors get paid when people like you upvote their post.
If you enjoyed what you read here, create your account today and start earning FREE STEEM!
Sort Order:  

[광고] 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]

image.png

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