function identity<Type>(arg: Type): Type {
return arg;
}
let output = identity<string>("myString");
<
와 >
로 감싸서 표현함let output = identity("myString");
function loggingIdentity<Type>(arg: Type): Type {
console.log(arg.length); // Error
return arg;
}
Type[]
로 선언해야함function loggingIdentity<Type>(arg: Type[]): Type[] {
console.log(arg.length);
return arg;
}
Array<Type>
으로 선언해도 됨function loggingIdentity<Type>(arg: Array<Type>): Array<Type> {
console.log(arg.length);
return arg;
}
extends
키워드로 Generic Type을 제약함extends
키워드 뒤 타입, 유니언 타입, 커스텀 타입 등 여러 타입이 들어갈 수 있음function merge<T extends object, U extends object>(objA: T, objB: U) {
return Object.assign(objA, objB);
}
const mergeObj = merge({name: 'Max', hobbies: ['Sport']}, {age: 30});
console.log(mergeObj);
interface Lengthwise {
length: number;
}
function loggingIdentity<Type extends Lengthwise>(arg: Type): Type {
console.log(arg.length);
return arg;
}
keyof
키워드로 Gereric Constraints를 제약함function getProperty<Type, Key extends keyof Type>(obj: Type, key: Key) {
return obj[key];
}
let x = { a: 1, b: 2, c: 3, d: 4 };
getProperty(x, "a"); // OK
getProperty(x, "m"); // Error
class DataStorage<T> {
private data : T[] = [];
addItem(item: T) {
this.data.push(item)
}
removeItem(item: T) {
this.data.splice(this.data.indexOf(item), 1)
}
getItems() {
return [...this.data];
}
}
const textStorage = new DataStorage<string>();
textStorage.addItem('Max');
textStorage.addItem('Manu');
textStorage.removeItem('Manu');
const numberStorage = new DataStorage<number>();
class DataStorage<T> {
private data : T[] = [];
addItem(item: T) {
this.data.push(item)
}
removeItem(item: T) {
if (this.data.indexOf(item) === -1) {
return;
}
this.data.splice(this.data.indexOf(item), 1)
}
getItems() {
return [...this.data];
}
}
const objStorage = new DataStorage<object>();
objStorage.addItem({name: 'Max'});
objStorage.addItem({name: 'Manu'});
objStorage.removeItem({name: 'Max'}); // 새로운 객체 {name: 'Max'}에 대해removeItem 메소드를 호출하므로 기존 객체에는 영향 받지 않음
console.log(objStorage.getItems()); // 예상치 못한 값 {name: 'Max'}가 나옴
const objStorage = new DataStorage<object>();
const maxObj = {name: 'Max'};
objStorage.addItem(maxObj);
objStorage.addItem({name: 'Manu'});
objStorage.removeItem(maxObj); // 같은 객체에 대해 removeItem 메소드를 호출하므로 지워짐
console.log(objStorage.getItems()); // {name: 'Manu'}
Partial<Type>
을 사용하면 Type의 모든 속성을 선택적으로 설정 가능한 타입을 만들 수 있음interface Todo {
title: string;
description: string;
}
function updateTodo(todo: Todo, fieldsToUpdate: Partial<Todo>) {
return { ...todo, ...fieldsToUpdate };
}
const todo1 = {
title: "organize desk",
description: "clear clutter",
};
const todo2 = updateTodo(todo1, {
description: "throw out trash",
});
Readonly<Type>
을 사용하면 Type의 모든 속성을 재할당할 수 없음interface Todo {
title: string;
}
const todo: Readonly<Todo> = {
title: "Delete inactive users",
};
todo.title = "Hello"; // Error
Pick<Type, property1| property2| ...>
을 사용하면 Type의 속성들을 조합하여 사용할 수 있음interface Todo {
title: string;
description: string;
completed: boolean;
}
type TodoPreview = Pick<Todo, "title" | "completed">;
const todo: TodoPreview = {
title: "Clean room",
completed: false,
};
Omit<Type, Keys>
를 사용하면 Type의 모든 속성들 중 Key들을 제거하여 사용할 수 있음interface Todo {
title: string;
description: string;
completed: boolean;
createdAt: number;
}
type TodoPreview = Omit<Todo, "description">;
const todo: TodoPreview = {
title: "Clean room",
completed: false,
createdAt: 1615544252770,
};
type TodoInfo = Omit<Todo, "completed" | "createdAt">;
const todoInfo: TodoInfo = {
title: "Pick up kids",
description: "Kindergarten closes at 5pm",
};
Exclude<UnionType, ExcludedMembers>
를 사용하면 Union Type의 멤버들 중에서 ExcludedMembers를 제외하여 사용할 수 있음type T0 = Exclude<"a" | "b" | "c", "a">;
// type T0 = "b" | "c"
type T1 = Exclude<"a" | "b" | "c", "a" | "b">;
// type T1 = "c"
type T2 = Exclude<string | number | (() => void), Function>;
// type T2 = string | number
type BooleanFields<T> = {
[K in keyof T]: boolean;
}
type BooleanFields<T> = {
[K in keyof T]: boolean;
};
type User = {
email: string;
name: string;
}
type UserFetchOptions = BooleanFields<User>;
// { email: boolean; name: boolean; }와 같은 형태임
type IsStringType<T> = T extends string ? true : false;
type IsStringType<T> = T extends string ? true : false;
type A = "abc";
type B = {
name: string;
};
type ResultA = IsStringType<A>; // true
type ResultB = IsStringType<B>; // false
infer
키워드를 사용하여 조건에 따라 추론된 타입을 사용함type GetReturnType<T> = T extends (...args: any[]) => infer U ? U : never;
type GetReturnType<T> = T extends (...args: any[]) => infer U ? U : never;
function someFunction() {
return true;
}
type ReturnTypeOfSomeFunction = GetReturnType<typeof someFunction>; // boolean
참고 링크 : TypeScript Handbook, How to Use Generics in TypeScript