Typescript Handbook / Developer’s Record 를 참고했습니다.
함수 타입
인자의 타입과 return type을 지정할 수 있다. 또한 익명함수도 만들 수 있어서 변수에 할당도 된다.
function add(x: number, y: number): number {
return x + y;
}
let myAdd = function(x: number, y: number): number { return x + y; };
함수 자체의 타입도 만들 수 있다.
let myAdd : (x: number, y: number) => number;
myAdd = function(x: number, y: number) {
return x + y
}
console.log(myAdd(3, 5) // 8
인자의 이름이 같을 필요는 없다.
let myAdd : (x: number, y: number) => number;
myAdd = function(a: number, b: number) {
return a + b
}
console.log(myAdd(3, 5) // 8
타입 추론
let myAdd : (x: number, y: number) => number;
myAdd = function(x, y) {
return x + y
}
console.log(myAdd(3, 10) // 8
Parameters
Optional
굳이 있어야 하는건 아니다~
라는 의미로 ?
를 쓴다.
function buildName(first: string, last?: string): string {
if(last) { return first + " " + last }
else { return first }
}
console.log(buildName("Yoon")) // Yoon
console.log(buildName("Yoon", "Byeongin")) // Yoon Byeongin
Default
기본으로 parameter의 값을 지정할 수 있다.
function 나이(나이: number, 붙임말="살"): string {
return 나이 + 붙임말 + " 입이다"
}
console.log(나이(15)) // 15살 입이다
console.log(나이(62, "세")) // 62세 입이다
만약에 default parameter가 앞에 있어야 한다면, undefined를 넣어 줘야한다.
function buildName(firstName = "Yoon", lastName: string): string {
return firstName + " " + lastName
}
console.log(buildName(undefined, "Byeongin")) // Yoon Byeongin
Rest
function 친구들이름불러보자(...친구들: string[]): string {
return 친구들.join(" ")
}
console.log(친구들이름불러보자("CPU", "마우스", "키보드", "모니터")) // CPU 마우스 키보드 모니터
This
this와 화살표 함수
let deck = {
suits: ["hearts", "spread", "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 }
}
}
}
let cardPicker = deck.createCardPicker()
let pickedCard = cardPicker()
console.log("card : " + pickedCard.card + " of " + pickedCard.suit)
[ERR]: Cannot read property 'suits' of undefined
this는 실행하는 환경에 의해 결정된다.
createCardPicker함수를 실행했을때 돌려받는건 함수이다. 그리고 이 함수를 실행할때는 (이 함수가 객체에 들어있는게 아니니까) this는 window가 된다.
하지만, 화살표 함수는 this를 미리 그 this가 지정된 객체로 바인딩 시켜준다.
let deck = {
suits: ["hearts", "spread", "clubs", "diamonds"],
cards: Array(52),
createCardPicker: function() {
return () => {
let pickedCard = Math.floor(Math.random() * 52)
let pickedSuit = Math.floor(pickedCard / 13)
return { suit: this.suits[pickedSuit], card: pickedCard }
}
}
}
let cardPicker = deck.createCardPicker()
let pickedCard = cardPicker()
console.log("card : " + pickedCard.card + " of " + pickedCard.suit)
// card : 50 of diamonds
작동은 하지만 this.suits[pickedSuit]
의 this
는 any
라는 단점이 있다.
this parameter
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),
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()
console.log("card : " + pickedCard.card + " of " + pickedCard.suit)
// card : 10 of spades
createCardPicker
의 인자값에 this: Deck
을 넣어주니까 this
의 데이터 타입을 Deck
으로 잡아준다!
callback 함수 안에있는 this
this 쓰지 말아주세요~
interface UIElement {
addClickListener(onclick: (this: void, e: Event) => void): void;
}
class Handler {
info: string,
onClickBad(this: Handler, e: Event) {
this.info = e.message
}
}
let h = new Handler();
uiElement.addClickListener(h.onClickBad)
이렇게 하면 에러가 뜬다.
Argument of type '(this: Handler, e: Event) => void' is not assignable to parameter of type '(this: void, e: Event) => void'. The 'this' types of each signature are incompatible. Type 'void' is not assignable to type 'Handler'.
this: void
라고 명시해줬는데 this: Handler
라고 했으니 당연히 오류가 난거다. 그래서 this: void를 맞춰줘야한다.
interface UIElement {
addClickListener(onclick: (this: void, e: Event) => void): void;
}
class Handler {
info: string,
onClickBad(this: void, e: Event) {
this.info = e.message
}
}
let h = new Handler();
uiElement.addClickListener(h.onClickBad)
callback함수에서 this써야할때
어떤 라이브러리의 함수에 callback함수로 내 함수를 넘겨줄때가 있다. 그 라이브러리에서 뭔가 처리하고 마지막에 callback함수로 내가 넘겨준 함수를 호출해 주는 경우가 그렇다. 이때 이 callback함수안에 this를 써야할 수도 있는데, 그럼 아래와 같이 화살표 함수를 써주면 된다.
interface UIElement {
addClickListener(onclick: (this: void, e: Event) => void): void;
}
class Handler {
info: string,
onClickGood = (e: Event) => {
this.info = e.message
}
}
let h = new Handler();
uiElement.addClickListener(h.onClickGood)
하지만, 화살표 함수의 단점은 메모리를 비교적 많이 잡아먹는다. method는 prototype에 붙어서 모든 object가 그 method를 공유하지만, 화살표함수는 클래스를 통해 object를 생성할때마다 계속 함수를 만들어낸다.
Overload
함수의 인자값으로 배열이 들어갈 수도 있고 객체가 들어갈 수도 있고, 아니면 그냥 숫자가 들어갈 수도 있다. 자바스크립트는 dynamic한 언어니까.
let suits = ["hearts", "spades", "clubs", "diamonds"]
function pickCard(x: any): any {
if (typeof x == "object") {
let pickedCard = Math.floor(Math.random() * x.length)
return pickedCard;
}
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)]
console.log("card: " + pickedCard1.card + " of " + pickedCard1.suit)
// card: 2 of diamonds
let pickedCard2 = pickCard(15)
console.log("card: " + pickedCard2.card + " of " + pickedCard2.suit)
// card: 2 of spades
들어가는거에 따라서 다르게 출력되는 이런상황... 타입스크립트에서는 어떻게 대응했을까? 타입스크립트스러운 방식은 다음과 같다.
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): any {
if (typeof x == "object") {
let pickedCard = Math.floor(Math.random() * x.length)
return pickedCard;
}
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)]
console.log("card: " + pickedCard1.card + " of " + pickedCard1.suit)
// card: 2 of diamonds
let pickedCard2 = pickCard(15)
console.log("card: " + pickedCard2.card + " of " + pickedCard2.suit)
// card: 2 of spades
let pickedCard3 = pickCard("i Love you")
타입스크립트에서는 이런식으로 overload를 한다. 이제 pickCard
함수는 2가지 모양을 가지게 된다. 주의할점은, pickCard
에 any
타입의 값을 넣으면 안된다. 위에 정한 2가지 타입만 들어갈 수 있다. 마지막에 적은 pickCard("i Love you")
는 다음과 같은 에러를 뿜는다.
No overload matches this call. Overload 1 of 2, '(x: { suit: string; card: number; }[]): number', gave the following error. Argument of type '"i Love you"' is not assignable to parameter of type '{ suit: string; card: number; }[]'. Overload 2 of 2, '(x: number): { suit: string; card: number; }', gave the following error. Argument of type '"i Love you"' is not assignable to parameter of type 'number'.
약간 복잡하긴 한데 그래도 쓸모는 있을것같다.