
제네릭 함수: 모든 타입에 두루두루 사용할 수 있는 범용 함수
제네릭은 선언 시점이 아니라 생성 시점에 타입을 명시하여 하나의 타입만이 아닌 다양한 타입을 사용할 수 있도록 하는 기법이다.
함수를 호출할 때 매개변수에 따라 타입이 달라진다.
function func<T>(value: T): T {
return value;
}
let num = func(10); // number type
let bool = func(true); // boolean type
let str = func('str'); // string type
<T>: 타입 변수
function swap<T, U>(a: T, b: U) {
return [b, a];
}
const [a, b] = swap('1', 2);
function returnFirstValue<T>(data: [T, ...unknown[]]) {
return data[0];
}
let num = returnFirstValue([0, 1, 2]);
let str = returnFirstValue([1, 'hello', 'mynameis']);
function getLength<T extends {length: number}>(data: T) {
return data.length;
}
let var1 = getLength([1,2,3]);
let var2 = getLength('12345');
let var4 = getLength({length: 10});
// map
function map<T, U>(arr: T[], callback: (item: T) => U) {
let result = [];
for(let i = 0; i < arr.length; i++) {
result.push(callback(arr[i]));
}
return result;
}
map(arr, (it) => it * 2);
map(['hi', 'hello'], (it) => parseInt(it));
// forEach
function forEach<T>(arr: T[], callback: (item: T) => void) {
for(let i = 0; i < arr.length; i++) {
callback(arr[i]);
}
}
forEach(arr2, (it) => {
console.log(it.toFixed());
});
forEach(['123', '456'], (it) => {
it;
})
interface KeyPair<K, V> {
key: K;
value: V;
}
let keyPair: KeyPair<string, number> = {
key: 'key',
value: 0,
}
let keyPair2: KeyPair<boolean, string[]> = {
key: true,
value: ['1'],
}
interface NumberMap {
[key: string]: number;
}
let numberMap1: NumberMap = {
key: -1234,
key2: 123123,
}
interface Map<V> {
[key: string]: V;
}
let stringMap: Map<string> = {
key: 'string',
}
let booleanMap: Map<boolean> = {
key: true,
}
type Map2<V> = {
[key: string]: V;
}
let stringMap2: Map2<string> = {
key: 'hello',
}
interface Student {
type: 'student';
school: string;
}
interface Developer {
type: 'developer';
skill: string;
}
interface User<T> {
name: string;
profile: T;
}
function goToSchool(user: User<Student>) {
const school = user.profile.school;
console.log(`${school}로 등교 완료`);
}
const developerUser: User<Developer> = {
name: 'dobby',
profile: {
type: 'developer',
skill: 'typescript',
}
}
const studentUser: User<Student> = {
name: 'sooyeon',
profile: {
type: 'student',
school: '전남대학교',
}
}
class List<T> {
constructor(private list: T[]) {}
push(data: T) {
this.list.push(data);
}
pop() {
return this.list.pop();
}
print() {
console.log(this.list);
}
}
const numberList = new List([1, 2, 3]);
numberList.pop();
numberList.push(4);
numberList.print();
const stringList = new List(['1', '2']);
stringList.push('hello');
자동으로 타입을 추론하는 기능을 가지고 있지 않다.
resolve의 타입은 정의할 수 있지만, reject에 대한 타입은 정의할 수 없다.
const promise = new Promise<number>((resolve, reject) => {
setTimeout(() => {
resolve(20); // number;
reject('~~ 때문에 실패');
}, 3000)
});
promise.then((response) => {
console.log(response * 10); // number
})
promise.catch((err) => {
if(typeof err === 'string') {
console.log(err);
}
});
프로미스를 반환하는 함수의 타입 정의
interface Post {
id: number;
title: string;
content: string;
}
function fetchPost(): Promise<Post> {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve({id: 1, title: '', content: ''});
}, 3000);
});
}
const postRequest = fetchPost();
postRequest.then((post) => {
post.id;
})