함수

zimablue·2023년 8월 13일

typescript

목록 보기
2/18

함수 매개변수 Annotation


// 			   (매개변수/ 콜론/ 타입)
function greet (person: string) {
  return `Hi there, ${person}!`
}

greet("soyeon");
// `Hi there, soyeon!`

// Argument of type 'number' is not assignable to parameter of type 'string'.
greet(3)



기본 매개변수

매개변수의 기본 값을 사용하려면 다음과 같이 사용하면 됩니다.

// 			   (매개변수/ 콜론/ 타입/ 기본값)
function greet (person: string = 'stranger') {
  return `Hi there, ${person}!`
}

greet();
// `Hi there, stranger!`



여러개의 매개변수

함수를 호출할 때 매개 변수만큼 인수를 전달해야하며 각 인수는 타입에 맞아야 합니다.

const doSomething = (person: string, age: number, isFunny: boolean) => {};

doSomething("soyeon", 32, true);

// Expected 3 arguments, but got 1
doSomething("soyeon");

//doSomething(person: string, age: number, isFunny: boolean): void
doSomething("ChickenFace", 78, 'think so');



return Type Annotation

소괄호(()) 다음에 return 할 타입 값을 지정합니다.

// (매개변수 Type Annotation): return Type Annotation
function square (num: number): number {
  return num * num;
};

// Type Inference
// 타입 애너테이션을 지정하지 않고 타입 추론을 통해 return에 어떤 타입 값이 할당되었는지 파악
// function square(num: number): number
function square(num: number) {
  return num * num;
}

square(3);



Void Type

return이 없다면 void 타입으로 적용됩니다.
void는 아무것도 반환하지 않는 함수의 반환 타입으로 사용합니다.
따라서 반환 값은 undefined를 갖습니다.

// function square(num: number): void
function square(num: number) {
  num * num;
}

// 사용 불가
// Type 'number' is not assignable to type 'void'
function square(num: number): void {
  return num * num;
}



Never Type

Never도 Void와 같이 아무것도 반환하지 않는 함수의 반환 타입으로 사용합니다.
차이점이라면 Void는 아무것도 반환하지 않은 경우 함수의 백그라운드에서 undefined 상태로 반환됩니다.
하지만 Never은 함수가 아무것도 반환하면 안 된다는 것을 나타내기 위해 쓰이고, 일반적으로 예외를 발생시키는 함수에 사용됩니다.

// void와 역할은 같지만 '절대 반환되면 안된다'는 의미를 전달 할 수 있는 경우

// 반환없이 에러만 발생하는 함수
function makeError(msg: string): never {
  throw new Error(msg);
}

// 반환없이 영원히 반복만 하는 함수
function gameLoop(): never {
  while (true) {
    console.log("GAME LOOP RUNNING");
  }
}



Union Type

return 값의 타입이 조건문에 따라 달라질 경우 |을 사용합니다.

// function rando(num: number): string | number
function rando(num: number) {
  if(Math.random() < 0.5) {
    return num.toString();
  }
  return num;
}



arrow function

화살표 함수의 Type Annotation은 아래와 같이 생겼습니다.

const add = (x: number, y: number): number => {
	return x + y;
}



anonymous functions

타입스크립트는 Type Inference를 하여 매개변수 color가 string 타입이라는 것을 알 수 있습니다.

const colors = ["red", "orange", "yellow"];
colors.map((color) => {
  return color.toUpperCase();
});



call signatures

call signatures는 함수의 인자와 반환 타입이 무엇인지 알려주는 것 입니다.

type alias로 call signatures를 만들 수 있습니다.

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

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

콜백 함수에도 적용할 수 있습니다.

// call signatures
type DescribableFunction = {
  // 속성 타입 지정
  description: string;
  // 인수 타입과 반환 타입 지정
  (someArg: number): boolean;
};

// 콜백 함수에 미리 작성한 call signatures를 적용
function doSomething(fn: DescribableFunction) {
  console.log(fn.description + " returned " + fn(6));
}
 
function myFunc(someArg: number) {
  return someArg > 3;
}
// myFunc의 속성 추가
myFunc.description = "default description";
 
doSomething(myFunc);
// 6이 3보다 크기 때문에 true

call signatures를 사용하면 함수 구현과 타입 지정을 분리하여 작성할 수 있는 이점이 생깁니다.



Overloading

오버로딩은 함수가 여러개의 call signatures를 가지고 있을 대 발생시킵니다.

// 여러개의 call signatures
type Add = {
  (a: number, b: number) : number
  (a: number, b: string) : number
}

// 인수 b가 number일 수도 string일 수도 있는 경우가 있음
const add: Add = (a, b) => {
  if(typeof b === "string") return a
  return a + b
}

인수의 개수에 따라 변하는 call signatures를 여러개 가지고 있을 수 있습니다.

// 여러개의 call signatures
type Add = {
  (a: number, b: number) : number
  (a: number, b: number, c: number) : number
}

// 인수 b가 number일 수도 string일 수도 있는 경우가 있음
const add: Add = (a, b, c?:number) => {
  if(c) return a + b + c
  return a + b
}



polymorphism

타입 스크립트에서 함수는 모두 다른 형태의 타입을 가질 수 있습니다.
매개변수의 숫자, 타입, 반환 타입 등에 따라 다양한 형태를 갖는 것을 Polymorphism이라고 합니다.


예시

배열의 값을 출력하는 함수를 사용하려고 합니다.
배열의 값의 타입은 어떤 것도 될 수 있을 때 아래와 같이 모든 가능성을 조합해서 call signatures를 구현해야 합니다.

type SuperPrint = {
	(arr: number[]):void
  	(arr: boolean[]):void
  	(arr: string[]):void
  	(arr: (number|boolean)[])
  	...
}

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

sperPrint([1, 2, 3, 4])
sperPrint([true, false, true, false])
sperPrint(["1", "2", "3", "4"])
superPrint([1, true, 3, false])
...

모든 가능성을 조합해서 call signatures를 구현해야 하는 일은 비효율적이고 이럴 때 제네릭을 사용합니다.

제네릭을 사용하면 다음과 같이 코드를 변경할 수 있습니다.

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

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

sperPrint([1, 2, 3, 4])
sperPrint([true, false, true, false])
sperPrint(["1", "2", "3", "4"])
superPrint([1, true, 3, false])
...

더 자세한 내용은 제네릭 게시글을 참고해 보시면 도움이 됩니다.

0개의 댓글