[TIL] TypeScript 2 - 함수

danbii·2020년 7월 14일
2

TypeScript

목록 보기
2/4

함수

함수의 타입

함수의 타입을 결정하기 위해서는 아래와 같이 두 가지 정보가 필요하다.

  • 매개변수(parameter)의 타입
  • 반환값(return value)의 타입 (반환 타입)

매개변수 (param1: number)

변수 타입을 나타낼 때와 같이 매개변수 뒤에 콜론(:)을 붙이고 타입을 적는다.

반환 타입 (function (): number {...})

매개변수를 닫는 괄호와()) 함수 본문을 여는 대괄호({) 사이에 콜론을 붙이고 타입을 적는다.

function sum(a: number, b: number): number {
  return (a + b);
}

함수가 아무 값도 반환하지 않는다면 반환 타입으로 void를 사용한다.

function logGreetings(name: string): void {
  console.log(`Hello, ${name}!`);
}

void 반환 타입을 갖는 함수가 undefinednull 이외의 값을 반환하면 타입 에러가 발생한다.
void가 아닌 반환 타입을 갖는 함수가 아무 값도 반환하지 않을 때도 에러가 발생한다.

function notReallyVoid(): void {
  return 1;
}
// void 형식을 매개변수로 갖기 때문에 1을 반환 할 수 없다.

function actuallyVoid(): number { }
// void 형식을 매개변수로 갖는데 아무 값도 반환하지 않는다.

함수 값의 타입 표기

함수 타입의 값에 타입 표기를 해주기 위해서는 화살표 함수 정의 문법과 비슷한 문법을 사용한다.

(...매개변수 나열) => 반환 타입

매개변수가 없는 함수는 매개변수를 생략할 수 있다.

( ) => 반환 타입

화살표 함수 문법을 사용한 함수도 비슷하게 정의가 가능하다.

const yetAnotherSum: (a: number, b: number) => number = sum;
const onePlusOne: () => number = () => 2;
const arrowSum: (a: number, b: number) => number = (a, b) => (a + b);

타입 별칭

기본 매개변수

ES6 처럼 타입스크립트에서도 기본 매개변수 문법을 사용할 수 있다.
매개변수명: 타입 = 기본값 형태로 나타낸다.

function greetings(name: string = 'person'): void {
  console.log(`Hello, ${name}`);
}
greetings('danbi'); // Hello, danbi!
greetings(); // Hello, person!

선택 매개변수

  • 많은 프로그래밍 언어는 함수를 정의할 때의 매개변수의 수보다 많거나 적은 수의 인자가 들어온 경우 에러가 발생한다. 그러나 자바스크립트는 더 들어온 인자는 버리고, 덜 들어온 인자는 undefined가 들어온 것처럼 함수를 실행한다.

  • 이런 언어의 특성 및 기존 사용법을 사용하면서 타입 안정성을 확보하기 위해 타입스크립트는 선택 매개변수를 지원한다. 함수의 매개변수명 뒤에 물음표(?)를 붙여 매개변수가 생략될 수도 있다는 것을 나타낸다.

  • 예를 들어, optional?: number로 선언된 선택 매개변호 optional을 함수 본문에서 number 타입 값으로 사용하려면 해당 값이 Undefined가 아닌지를 먼저 검사한다.

function fetchVideo(url: string, subtitleLanguage?: string) {
  const option = { url };
  if (subtitleLanguage) {
    option.subtitleLanguage = true;
  }
  /* ... */
}
fetchVideo('https://example.com', 'ko'); // okay
fetchVideo('https://example.com'); // also okay

이 때 위의 매개변수를 정의할 때 위의 코드 순서 처럼이 아니라 아래 순서 처럼 선택 매개변후 이후에 필수 매개변수가 오면 에러가 발생한다.

function invalidFetchVideo(subtitleUrl?: string, url: string) {
  // 에러 발생
}

에러가 발생하는 이유는 필수 매개변수가 선택 매개변수 뒤에 있을 때, 인자가 어떤 매개변수의 값인지 구분할 수 없기 때문이다.

fetchVideo('https://example.com');
invalidFetchVideo('https://example.com');

📌 위에서 처럼 함수를 호출할 때, fetchVideo('https://example.com') 함수 호출의 인자가 url 매개변수 값이라는 것은 알 수 있지만 invalidFetchVideo('https://example.com') 호출에서는 'https://example.com'의 값이 subtitleUrl의 값으로 쓰이는 건지 url의 값으로 쓰이는 건지 정확히 알 수 없다.
타입스크립트는 이런 식으로 함수를 정의하면 에러가 발생한다.

함수 오버로딩

자바스크립트에서 한 함수가 여러 쌍의 매개변수와 반환 타입 쌍을 갖는 경우가 많다.
이렇게 함수 타입을 정의할 수 있게 타입스크립트는 함수 오버로딩(function overloading)을 지원한다.

타입스크립트의 함수 오버로딩 특징

  • 함수는 하나 이상의 타입 시그니처를 가질 수 있다.
  • 함수는 단 하나의 구현을 가질 수 있다.

오버로딩을 통해서 여러 형태의 함수 타입을 정의할 수 있지만, 실제 구현은 한 번만 가능하다.

아래 세 함수를 함수 오버로딩을 사용해 double이라는 함수로 나타낸다.

// 타입 시그니쳐 정의
function double(str: string): string;
function double(num: number): number;
function double(arr: boolean[]): boolean[];

// 함수 본문 구현
function double(arg) {
    if (typeof arg === 'string') {
        return `${arg}${arg}`;
    } else if (typeof arg === 'number') {
        return arg * 2;
    } else if (Array.isArray(arg)) {
        return arg.concat(arg);
    }
}

// double 함수는 호출하는 인자의 타입에 따라 반환 타입이 달라진다.
const num = double(3); // number
const str = double('ab'); // string
const arr = double([true, false]); // boolean[]

This 타입

자바스크립트 함수 내부에서의 this는 함수가 정의되는 시점이 아닌 실행되는 시점에 결정된다. 이 때 함수 내부에서 this의 타입을 결정하는 것이 어렵다.
타입스크립트는 이것을 해결하기 위해 함수 내에서 this의 타입을 정한다.

함수의 this 타입을 정하기 위해서 함수의 타입 시그니쳐에서 매개변수 가장 앞에 this를 추가해야 한다. 이때 this 타입은 타입 시스템을 위해서만 존재한다. this 매개변수를 추가한다고 해도 함수가 받는 인자 수나 실제 동작은 변하지 않는다.

interface HTMLElement {
  tagName: string; 
}
interface Handler {
  (this: HTMLElement, event: Event, callback: () => void): void;
}
let cb: any;
// 실제 함수 매개변수에는 this가 나타나지 않음
const onClick: Handler = function(event, cb) {
  // this는 HTMLElement 타입
  console.log(this.tagName);
  cb();
}

this의 타입을 void로 정하면 함수 내부에서 this에 접근하지 못하게 할 수 있다.

interface NoThis {
  (this: void): void;
}
const noThis: NoThis = function() {
  console.log(this.a); // 속성 a는 void 타입에 존재하지 않는다.
}

실제 프로젝트에서 사용

const LogInView: React.FunctionComponent<RouteComponentProps> = (props) => {
  const viewModel: UserViewModel = container.get<UserViewModel>(
    "UserViewModel"
  );
  • LogInView 컴포넌트가 받을 Props를 React.FunctionComponent로 정의 해주었다.
const userValidateHandler = (e: any) => {
    if (!e.target.value) {
      console.log("아이디와 비밀번호를 입력 해주세요");
    }
    return false;
  };
  • 로그인 화면을 만들 때 화살표 함수 안에 이벤트 자체도 e: any로 타입을 지정해 줄 수 있다.
profile
룰루랄라! 개발자 되고 싶어요🙈

0개의 댓글