[TypeScript] TypeScript의 함수

윤후·2022년 6월 16일
0

TypeScript

목록 보기
2/7

TypeScript의 Function


Function

Call Signatures

함수의 타입을 만들고 싶을 때 사용한다.

const add = (a : number, b : number) => a + b

위와 같이 선언된 함수가 있다고 했을 때, a와 b의 타입을 모두 선언해주고 있다. 위와 같은 변수의 사용이 많다면 Call Signatures를 지정하고 불러와 사용할 수 있다.

type Add = (a : number, b : number) => number;

const add : Add = (a, b) => a + b

함수를 선언하기전 타입을 만들고 함수가 어떻게 작동하는지 지정해 둘 수 있게 되는것이다.

Overloading

함수가 여러개의 Call signatures를 가지고 있을 때 발생시킨다.

type Add = {
	(a : number, b : number) : number
	(a : number, b : string) : number
}

const add : Add = (a, b) => a + b // 오류 발생

b의 type이 string | number이기 때문에 에러가 발생하게 된다.
다른 예시를 통해 조금 더 살펴보자면,

type Config = {
	path : string,
	state : object
}

type Push = {
	(path : string) : void
	(config : Config) : void
}

const push : Push = (config) => {
	if(typeof config === "string"){
		console.log(config)	// config라는 타입이 string이라는걸 알고 있다.
	} else {
		console.log(config.path, config.state) // config라는 타입이 Config이라는걸 알고 있다.
	}
}

type으로 선언해준 Config가 객체의 형태이기 때문에 config.path, config.state로 접근이 가능하다.

여러개의 argument를 가지고 있을 경우

type Add = {
	(a: number, b: number) : number
	(a: number, b: number, c: number) : number
}

const add : Add = (a, b, c) => {
	return a + b
}

위와 같은 예제를 살펴보면, c라는 매개변수는 현재 옵션과 같은 것이다. 즉, Add를 부를 때, a와 b를 부를 수도 있고, 또는 a, b, c,를 부를 수 있다. 결국 c는 옵션이라는 것이다.

그렇다면 옵션이라는 값을 어떻게 지정해두면 될까?

type Add = {
	(a: number, b: number) : number
	(a: number, b: number, c: number) : number
}

const add : Add = (a, b, c? : number) => {
	return a + b
}

앞에서 배웠듯 "?"를 사용하여 optional하게 만들어주면 되겠다.

Polymorphism (다형성)

type SuperPrint = {
	(arr :number[]) : void
}

const superPrint : Superprint = (arr) => {
	arr.forEach(i => console.log(i))
}

call signature를 작성할 때 여기 들어올 확실한 타입을 모를 때, generic을 사용한다.

위와 같은 예제가 있다고 했을 경우, 타입에 상관없이 함수가 출력될 수 있도록 하려면 어떻게 해야할까?

현재 arr에는 number만 들어가서 출력이 아무거나(void)로 출력이 될 수 있도록 설정해 놓은 것이다. arr을 number인지, boolean인지 string인지 하나하나 지정해서 입력하는게 아닌 void처럼 선언할 수 없을까?

⇒ generic형식을 사용하면 된다.

generic이란 타입의 placeholder같은 것이다. TypeScript가 어떤 타입인지 알게 유추하도록 하는 것이다.

generic을 사용한다고 TypeScript에 선언만 하면 된다.

type SuperPrint = {
	<TypePlaceholder>(arr : TypePlaceholder[]) : void
}

const superPrint : Superprint = (arr) => {
	arr.forEach(i => console.log(i))
}

console.log(superPrint([1, 2, 3, 4])) // const superPrint : <number>(arr: number[]) => void
console.log(superPrint([false, true, false, false])) // const superPrint : <boolean>(arr: boolean[]) => void
console.log(superPrint([1, 2, false, ture])) // const superPrint : <number|boolean>(arr: (number|boolean)[]) => void
console.log(superPrint(["1", "2", true, 1])) // const superPrint : <number|boolean|string>(arr: (number|boolean|string)[]) => void

현재 위의 예제에서는 아무것도 리턴되지 않고 console.log만 찍어내고 있을 뿐이다. 만약, return 하는 값이 있다면 그 때의 값을 어떻게 generic하게 설정해주면 될까?

type SuperPrint = {
	<TypePlaceholder>(arr : TypePlaceholder[]) : TypePlaceholder
}

const superPrint : Superprint = (arr) => arr[0]

console.log(superPrint([1, 2, 3, 4])) // const superPrint : <number>(arr: number[]) => number
console.log(superPrint([false, true, false, false])) // const superPrint : <boolean>(arr: boolean[]) => boolean
console.log(superPrint([1, 2, false, ture])) // const superPrint : <number|boolean>(arr: (number|boolean)[]) => number|boolean
console.log(superPrint(["1", "2", true, 1])) // const superPrint : <number|boolean|string>(arr: (number|boolean|string)[]) => number|boolean|string

간단하다. void 선언 대신에, return하는 값의 type을 generic으로 바꿔주면 되겠다.

Generics Recap

위와 같이 설정해준 generic을 한 가지 뿐만아닌 여러가지를 사용하고 싶을 때는 어떻게 하면 될까?

type SuperPrint = {
	<T, M>(a: T[], b :M) => T
}

const superPrint : SuperPrint = (arr) => arr[0]

console.log(superPrint([1, 2, 3])) // 에러 발생 TypeScript는 2개의 변수가 들어가도록 지정되어 있는데, 1개만 들어가있기 때문에.
console.log(superPrint([1, 2, 3], "x"))

간단하다. generic의 선언에 하나의 generic을 추가하여 선언해주면 되겠다.

profile
궁금한걸 찾아보고 공부해 정리해두는 블로그입니다.

0개의 댓글