
타입 스크립트에서 함수를 표현하는 방법은 여러가지이다.
function add(x: number, y: number):number {
return x + y
}
const add = function(x: number, y: number):number {
return x + y
}
const add = (x: number, y: number):number => {
return x + y
}
문자열을 string, 정수배열을 number[] 로 표현했듯이 함수 역시 함수를 표현하는 타입을 미리 선언 가능하다.
함수 타입을 미리 선언하고 뒤에 함수식을 붙여넣으면,
함수 매개변수에서 타입을 또 선언하지 않아도 된다는 특징이 있다.
// 변수에 미리 함수 타입을 지정
let myFunc4: (arg1: number, arg2: number) => number;
myFunc4 = function (x, y) {
return x + y;
};
// 위의 과정을 한줄로 표현
let myFunc5: (arg1: number, arg2: number) => number = (x, y) => {
return x + y;
};
하지만 대부분의 개발자들은 변수에 미리 함수 타입을 지정하지 않는다.
대부분 interface , type 별칭을 사용하여 함수 타입을 정의해서 사용한다.
interface Add2 {
(x: number, y: number): number;
}
let myFunc7: Add2 = (x, y) => {
return x + y;
};
타입스크립트에서는 함수의 인자를 모두 필수 값으로 간주한다.
따라서, 함수의 매개변수를 설정하면 심지어 인자값이 undefined나 null 같은 쓸모없는 값이이라도
인자로 넘겨야하며, 컴파일러에서는 정의된 매개변수 값이 넘어 왔는지 확인한다.
function sum(a: number, b: number): number {
return a + b;
}
sum(10, 20); // 30
sum(10, 20, 30); // error, too many parameters
만약 매개변수가 유동적으로 변하는 함수를 만들고 싶다면 어떻게 해야 할까?
매개변수의 갯수 만큼 인자를 넘기지 않아도 되게 만들고 싶다면, 선택적(optional) 키워드인
물음표(?)를 이용하면 된다.
단, 선택적 매개변수를 사용할때 주의할점은 선택적 매개변수가
이외의 함수 인자 앞으로 위치하면 안되는 것이다. (선택적 매개변수는 무조건 뒤로 위치)
만일 옵셔널 매개변수를 앞에다 꼭 두고 사용하고 싶다면,
같은 타입 동작인 유니온 타입 ( number | undefined )으로 선언하면 된다.
하지만 추천하지는 않는 방법이니 뒤로 위치시키는 것을 추천한다.
// function sum(a: number, b: number | undefined): number {} 이랑 같다.
function sum(a: number, b?: number): number {
return a + b;
}
sum(10, 20); // 30
sum(10); // 타입 에러 없음
만일 이렇게 b의 값을 전달하지 않으면 b 는 undefined 를 할당 받는다.
그래서 Null 병합 연산자( ?? )를 사용하여 null 또는 undefined인 경우
0을 반환하도록 지정하는 식으로 처리가 가능하다.
function add(a: number, b?: number, c?: number): number {
return a + (b ?? 0) + (c ?? 0);
}
add(1, 2, 3); // 6
add(1, 2); // 3
add(1); // 1
기본값을 할당한 매개변수의 함수 타입을 보면 옵셔널 파라미터(선택적 매개변수)가 적용된 걸 확인 할 수 있다.
왜냐하면 매개변수에 기본 값이 있으면 매개변수에 값을 할당 하지 않아도 된다는 의미가 되기 때문이다.
더불어 기본 값이 있으면 굳이 인자 타입을 선언하지 않아도 된다. 타입스크립트에선 이를 타입 추론이라 칭한다.
// 매개변수 기본 값이 있으면 굳이 인자 타입을 선언하지 않아도 된다 (타입 추론)
function sum(a: number, b = 100): number {
return a + b;
}
sum(10, undefined); // 110
sum(10); // 110
sum(10, 10) // 20
function aa(...numList: number[]): number[] {
return numList
}
aa([1,2,3,4])
named parameters는 함수 아규먼트 부분 전체를 객체로 감싸주고, 그 뒤에 타입을 정의를 해주는 방식이다.
마치 자바스크립트의 구조분해 문법을 타입으로 구현한 것이라고 할 수 있다.
함수의 "아규먼트(arguments)"는 함수를 호출할 때 함수에 전달되는 값들을 말합니다.
다른 말로 하면, 함수를 호출할 때 함수에 넘겨지는 값들이 함수 내부의 매개변수(parameter)에 할당됩니다.
function getText({ name, age = 15, language }: { name: string; age?: number; language?: string }): string {
const nameText = name.substr(0, 10);
const ageText = age >= 35 ? 'senior' : 'junior';
return `name: ${nameText}, age: ${ageText}, language: ${language}`;
}
getText({ name: '홍길동', age: 11, language: 'kor' });
getText({ name: '홍길동' });
왜 이렇게 이상한 문법이 다 있어? 라고 생각할 수도 있지만 아규먼트의 타입 정보를 뒤에다 내뺌으로써,
한눈에 함수 아규먼트 구성을 볼수 있기 때문에 사용한다.
이렇게 사용하기 힘들다면 interface 를 사용하면 된다.
interface User {
name: string
age?: number
language?: string
}
function getText(user: User): string {
const nameText = user.name.substr(0, 10);
const ageText = user.age >= 35 ? 'senior' : 'junior';
return `name: ${nameText}, age: ${ageText}, language: ${user.language}`;
}
getText({ name: '홍길동', age: 11, language: 'kor' });
getText({ name: '홍길동' });
만약 이러한 코드가 있다면 오류가 발생할까 발생하지 않을까?
interface User {
name: string;
age: number;
}
function join(name: string, age: number | string): User | string {
if (typeof age === 'number') {
return { name, age };
} else {
return '나이는 숫자로 입력해 주세요';
}
}
정답은 발생한다. 컴파일러가 이렇게 경고를 주는 이유는, 컴파일러 입장에서 join 함수가 User를 반환할지 string을 반환할지 확신이 없기 때문이다.
코드 상에서는 분명 if 문으로 분기처리가 잘 되어있지만,
타입만 놓고 봤을때는 확신이 없기 때문에 컴파일러가 에러를 주는 것이다.
이에 2가지 방법이 있다.
function join(name: string, age: number | string): User | string {
if (typeof age === 'number') {
return { name, age };
} else {
return '나이는 숫자로 입력해 주세요' as string;
}
}
interface User {
name: string;
age: number;
}
function join(name: string, age: number): User;
function join(name: string, age: string): string;
function join(name: string, age: number | string): User | string {
if (typeof age === 'number') {
return { name, age };
} else {
return '나이는 숫자로 입력해 주세요';
}
}