function getInfoText(name: string, age: number): string {
// 매개 변수 타입과 반환 타입 지정
const nameText = name.substr(0, 10); // 매개변수 name은 문자열 타입이기 때문에 substr 사용 가능
const ageText = age >= 35 ? 'senior' : 'junior'; // 매개변수 age는 숫자이기 때문에 다른 숫자와 크기 비교 가능
return `name: ${nameText}, age: ${ageText}`;
}
const v1: string = getInfoText('mike', 23);
const v2: string = getInfoText('mike', '23'); // TypeError
const v3: number = getInfoText('mike', 23); // TypeError
JS에서 함수는 일급객체이므로(Javascript Deep Dive - 함수(12) 편에서 설명하였다.) 함수를 변수에 저장할 수 있다.
함수를 저장할 변수의 타입은 다음과 같이 화살표 기호를 이용한다.
const getInfoText: (name: string, age: number) => void = function (name, age) {
// ...
};
선택 매개변수는 반드시 입력하지는 않아도 되는 매개변수다.
매개변수 이름 오른쪽에 물음표 기호를 입력하면 선택 매개변수가 된다.
function getInfoText(name: string, age: number, language?: string): string {
const nameText = name.substr(0, 10);
const ageText = age >= 35 ? 'senior' : 'junior';
const languageText = language ? language.substr(0, 10) : '';
return `name: ${nameText}, age: ${ageText}, language: ${languageText}`;
}
const v1: string = getInfoText('mike', 23, 'ko');
const v2: string = getInfoText('mike', 23); // language에 해당하는 인수는 반드시 입력하지는 않아도 괜찮다.
const v3: number = getInfoText('mike', 23, 123); // Type Error
function getInfoText(name: string, language?: string, age: number): void {
// 매개변수 age에서 타입 에러 발생!
}
다음은 선택 매개변수 오른쪽에 필수 매개변수가 온 경우다. 이럴 경우 컴파일 에러가 발생한다.
위의 코드를 에러 없이 구현하려면 다음과 같이 undefined를 이용한다.
function getInfoText(name: string, language: string | undefined, age: number): void {
// ...
}
유니온 타입을 이용해 undefined도 입력할 수 있도록 한다.
컴파일 에러가 발생하지는 않지만 가독성이 좋지 않다.
매개변수의 개수가 많은 경우에는 비구조화 문법을 이용해서 명명된 매개변수로 작성하는 게 좋다.
function getInfoText(name: string, ...rest: string[]): void {
// ...
}
다음과 같이 함수의 this 타입을 정의하지 않으면 기본적으로 any 타입이 사용된다.
앞에서도 말했듯 any타입은 가급적 사용하지 않는 것이 좋으므로(Any 타입을 남발하는 것을 TS를 제대로 활용하지 못하는 것이다.) this타입을 정의해 두는게 좋다.
// this타입을 정의하지 않은 코드
function getParam(this: string, index: number): string {
const params = this.splt(',');
if (index < 0 || params.length <= index) return '';
return this.split(',')[index];
}
splt
라고 오타를 냈다. 그러나 this타입이 any가 되었기 때문에 컴파일 에러가 발생하지 않는다.// this타입을 정의한 코드
function getParam(this: string, index: number): string {
const params = this.splt(','); // 타입 에러 발생
if (index < 0 || params.length <= index) return '';
return this.split(',')[index];
}
함수의 this타입은 다음과 같이 첫 번째 매개변수 위치에서 정의할 수 있다.
매개변수 index는 두번째 자리에 정의되어 있따. 그러나 this 타입은 매개변수가 아니므로 index가 첫 번째 매개변수가 된다.
this의 타입을 정의했기 때문에 splt
오타에서 타입 에러가 발생한다.
interface String {
getParam(this: string, index: number): string; // 인터페이스를 이용해 이미 존재하는 문자열 타입에 getParam 메서드를 추가한다.
}
String.prototype.getParam = getParam; // 문자열의 프로토타입에 작성한 함수를 등록한다.
console.log('asdf, 1234, ok '.getParam(1)); // 이제 문자열에 등록된 getParam 메서드를 호출할 수 있다.
JS는 동적 타입 언어이므로 하나의 함수가 다양한 매개변수 타입과 반환 타입을 가질 수 있다.
함수 오버로드(overload)를 사용하면 하나의 함수에 여러 개의 타입을 정의할 수 있다.
add 함수를 만들어 다음과 같은 일을 처리하고 싶다고 가정해보자.
- 두 매개변수가 모두 문자열이면 문자열을 반환한다.
- 두 매개변수가 모두 숫자이면 숫자를 반환한다.
- 두 매개변수를 서로 다른 타입으로 입력하면 안된다.
function add(x: number | string, y: number | string): number | string {
if (typeof x === 'number' && typeof y === 'number') return x + y;
else {
const result = Number(x) + Number(y);
return result.toString();
}
}
const v1: number = add(1, 2); // Type Error - 모든 매개변수가 숫자이면 반환값도 숫자이지만 Type Error가 발생한다.
console.log(add(1, '2')); // 두 매개변수의 타입이 달라도 Type Error가 발생하지 않는다.
// 매개변수와 반환 타입의 모든 가능한 조합을 정의한다.
function add(x: number, y: number): number;
function add(x: string, y: string): string;
// 실제 구현하는 쪽에서 정의한 타입은 함수 오버로드의 타입 목록에서 제외된다.
function add(x: number | string, y: number | string): number | string {
if (typeof x === 'number' && typeof y === 'number') return x + y;
else {
const result = Number(x) + Number(y);
return result.toString();
}
}
const v1: number = add(1, 2);
console.log(add(1, '2')); // TypeError: 두 매개변수의 타입이 다르면 타입에러가 발생한다.
// 우선 모든 매개변수의 이름을 정의한다.
function getInfoText({
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}`;
}
interface Param {
name: String;
age?: number;
language?: string;
}
function getInfoText({ name, age = 15, language }: Param): string {
const nameText = name.substr(0, 10);
const ageText = age >= 35 ? 'senior' : 'junior';
return `name: ${nameText}, age: ${ageText}, language: ${language}`;
}