이어서 타입스크립트의 함수에 대한 이야기를 해보자.
타입스크립트 핸드북(타입스크립트 핸드북)을 보고 공부한 것을 정리한 글입니다.
기본적인 JS 지식은 가진 상태라고 가정합니다.
웹 애플리케이션을 구현할 때 자주 사용되는 함수는 타입스크립트로 크게 다음 3가지 타입을 정의할 수 있다.
즉 함수의 파라미터, 반환값, 구조에 대해서 각각 별도의 타입을 지정해줄 수 있다는 말이다.
다음 자바스크립트 함수를 보자.
function sum(a, b) {
return a + b;
}
위의 함수에 타입을 부여하면 다음과 같다.
function sum(a: number, b: number): number {
return a + b;
}
기존 자바스크립트 함수 선언 방식에서 매개변수와 함수의 반환 값에 타입을 추가하였다.
만일 함수가 아무 반환값이 없다고 하면
void
를 사용하도록 하자.
타입스크립트에서는 함수의 인자를 모두 필수 값으로 간주한다. 따라서 함수의 매개변수를 설정하면 undefined
나 null
값이라도 무조건 넘겨야 하며, JS로 컴파일하는 과정에서 정의된 매개변수 값이 넘어왔는지 확인한다.
다시 말해 정의된 매개변수 값만 받을 수 있고 추가로 인자를 받을 수 없다는 의미이다.
다음 코드를 살펴보자.
function sum(a: number, b: number): number {
return a + b;
}
sum(10, 20); // 30
sum(10, 20, 30); // error, too many parameters
sum(10); // error, too few parameters
위와 같은 특성은 정의된 매개변수의 갯수 만큼의 인자를 넘기지 않아도 되는 자바스크립트의 특성과 반대된다. 만일 이런 특성을 살리고 싶다면 ?
를 이용해 다음과 같이 정의할 수 있다.
function sum(a: number, b?: number): number {
return a + b;
}
sum(10, 20); // 30
sum(10, 20, 30); // error, too many parameters
sum(10); // 10
ES6 문법과 같은 방식으로 매개변수 초기화를 진행할 수 있다.
function sum(a: number, b = '100'): number {
return a + b;
}
sum(10, undefined); // 110
sum(10, 20, 30); // error, too many parameters
sum(10); // 110
rest
메소드를 이용해 다음과 같이 함수를 작성할 수 있다.
function sum(a: number, ...nums: number[]): number {
const totalOfNums = 0;
for (let key in nums) {
totalOfNums += nums[key];
}
return a + totalOfNums;
}
//기존 숫자 a와 다른 숫자로 된 배열을 대입하면 해달 배열에 있는 숫자들을 모두 a에 더한 값을 반환.
타입스크리비트에서 자바스크립트의 this
가 잘못 사용되었을 때 감지할 수 있다.
타입스크립트에서 this
의 타입을 명시하려면 다음과 같은 방법을 사용한다.
function 함수명(this: 타입) {
// ...
}
이를 실제로 적용한 코드는 아래와 같다.
interface Vue {
el: string;
count: number;
init(this: Vue): () => {};
}
// interface는 타입이나 객체의 형태를 정의해주는 친구라고 우선 알아만 두자.
// 뒤에서 다루게 된다.
let vm: Vue = {
el: '#app',
count: 10,
init: function(this: Vue) {
return () => {
return this.count;
}
}
}
let getCount = vm.init();
let count = getCount();
console.log(count); // 10
앞에서 살펴본 일반적인 상황에서의 this
와는 다르게 콜백으로 함수가 전달되었을 때의 this
를 구분해줘야 할 때가 있다. 그럴 때는 아래와 같이 강제할 수 있는데, 코드를 살펴보자.
interface UIElement {
// 아래 함수의 `this: void` 코드는 함수에 `this` 타입을 선언할 필요가 없다는 의미입니다.
addClickListener(onclick: (this: void, e: Event) => void): void;
}
class Handler {
info: string;
onClick(this: Handler, e: Event) {
// 위의 `UIElement` 인터페이스의 스펙에 `this`가 필요없다고 했지만 사용했기 때문에 에러가 발생합니다.
this.info = e.message;
}
}
let handler = new Handler();
uiElement.addClickListener(handler.onClick); // error!
this
는 위의 코드에서는 이벤트리스너의 타겟이 되어야 하기 때문에 this
가 Handler
를 가리키지 못하도록 void
로 지정하는 것이다. 위의 코드에서 this:void
를 통해 onClick
함수 내에 this
를 지정하지 않아도 된다고 했으나 지정했기에 에러가 발생한다.
만일 UIElement
인터페이스의 스펙에 맞춰 Handler
를 구현하려면 다음과 같이 변경해야한다.
class Handler {
info: string;
onClick(this: void, e: Event) {
// `this`의 타입이 void이기 때문에 여기서 `this`를 사용할 수 없습니다.
console.log('clicked!');
}
}
let handler = new Handler();
uiElement.addClickListener(handler.onClick);
Tip
변수에 화살표 함수를 연결하면 매번 함수가 생성되지만, 클래스의 메소드로 선언하면 모든 핸들러에 기본으로 공유되므로 한번만 생성된다!
다음에는 인터페이스에 대한 이야기를 해보자.