-
타입스크립트 강의 내용 정리 (2)et cetera/TIL 2021. 12. 23. 19:48반응형
■ 제네릭(Generic)
function logText(text: string): string { console.log(text); return text; } function logNumber(num: number): number { console.log(num); return num; } logText('a'); logNumber(10);
유사한 함수를 두 개 선언하고 있다.
이 경우, 코드를 줄일 수 있는 방법은 크게 union 타입을 활용하는 방법과 Generic을 사용하는 방법이 있다.
// union type을 통한 해결 function logText(text: string | number) { console.log(text); return text; }
이 방법을 사용하면 함수 내부에서는 string과 number가 공통으로 가지는 속성만 사용할 수 있다.
logText에서 반환되는 값 역시 string | number 타입이므로 split 같은 것들은 사용 불가능.// Generic을 통한 해결 function logText<T>(text: T): T { console.log(text); return text; } // 인터페이스에 제네릭 선언하기 interface DropdownItem<T> { value: T; selected: boolean; }
인터페이스에 제네릭을 사용해서 선언하면 타입 코드를 줄일 수 있다는 장점이 있다.
■ 제네릭(Generic)의 타입 제한
function logTextLength<T>(text: T): T { console.log(text.length); // 에러 return text; } logTextLength('hi');
타입스크립트 입장에서는 T에 어떤 타입이 들어올지 모르기 때문에 text가 length 속성을 가지고있는지 알 수가 없다.
function logTextLength<T>(text: T[]): T[] { console.log(text.length); text.forEach(function(text) { console.log(text); }); return text; } logTextLength<string>(['hi', 'abc']);
length 속성을 가지고 있을거라는 힌트를 배열을 통해 줄 수 있다.
■ 제네릭(Generic)의 타입 제한 2 - 정의된 타입 활용하기(확장)
interface LengthType { length: number; } function logTextLength<T extends LengthType>(text: T): T { console.log(text.length); return text; }
요 제네릭은 LengthType의 하위 타입일 것이라고 제한해주는 것.
(해당 제네릭에 들어올 타입은 length 속성을 무조건 가져야 한다)■ 제네릭(Generic)의 타입 제한 3 - keyof
interface ShoppingItem { name: string; price: number; stock: number; } function getShoppingItemOption<T extends keyof ShoppingItem>(itemOption: T): T { return itemOption; } getShoppingItemOption('name');
'ShoppingItem에 있는 속성 key들 중에 하나가 인자가 된다' 라는 의미.
즉, T에는 name, price, stock를 포함하는 타입이 들어간다.
매개변수가 ShoppingItem 인터페이스의 속성들만 가질 수 있게 제약하는 방법.■ Promise의 타입
Promise의 타입은 기본적으로 제네릭을 사용하여 정의되어 있다.
Promise가 fulfilled 되었을 때 반환될 값의 타입을 제네릭에다가 채워주면 된다.function fetchItems(): Promise<string[]> { const items = ['a', 'b', 'c']; return new Promise(function (resolve) { resolve(items); }); } fetchItems();
■ enum의 값들 중에서 하나를 갖게 하는 타입
enum PhoneType { Home = 'home', Office = 'office', Studio = 'studio', } findContactByPhone(phoneNumber: number, phoneType: PhoneType): Contact[] { return this.contacts.filter( contact => contact.phones[phoneType].num === phoneNumber ); }
phoneType 인자에는 PhoneType.Home / PhoneType.Office / PhoneType.Studio 중 하나만 들어갈 수 있다.
■ 제네릭의 타입 추론
interface Dropdown<T> { value: T; title: string; } interface DetailedDropdown<K> extends Dropdown<K> { description: string; tag: K; } const detailedItem: DetailedDropdown<number> = { title: 'abc', description: 'ab', value: 10, // number로 추론 tag: 2 // number로 추론 }
■ DOM API의 타입 단언
const div = document.querySelector('div');
코드가 실행되는 시점에 이 DOM 이 존재하는지 확신하지 못한다.
그래서 타입이 HTMLDivElement | null 이 됨.
여기서 if문을 통해 타입을 좁혀주거나(null을 걸러주거나) 타입 단언을 사용해주면 된다.// if문 const div = document.querySelector('div'); if (div) { console.log(div.innerText); } // 타입 단언 const div = document.querySelector('div') as HTMLDivElement; console.log(div.innerText);
■ 타입 가드 함수
interface Developer { name: string; skill: string; } interface Person { name: string; age: number; } function isDeveloper(target: Developer | Person): target is Developer { return (target as Developer).skill !== undefined; }
is 키워드를 사용해서 target 인자가 Developer인지 아닌지를 boolean 값으로 반환하는 함수
원래 target은 Developer | Person이므로, 함수 내부에서는 둘의 공통 속성인 name만 사용할 수 있는데
타입 가드를 통해서 if문으로 분기를 쳐주면 isDeveloper가 true일 때는 내부에서 skill을 사용할 수 있고
isDeveloper가 false일 때는 그 내부에서 age를 사용할 수 있게된다.if (isDeveloper(someone)) { console.log(tony.skill); } else { console.log(tony.age); }
■ 타입 호환
구조적 타이핑과 연관되는 개념.
속성을 더 많이 가질수록 더 작은 타입이고, 속성을 더 적게 가질수록 더 큰 타입이다.
구조적으로 더 작은 타입은 더 큰 타입을 지원하지 않는다.
즉, 더 작은 타입의 변수에 더 큰 타입의 변수를 할당할 수 없다.interface Developer { name: string; skill: string; } interface Person { name: string; } let developer: Developer; let person: Person; developer = person; // X person = developer; // O
interface Developer { name: string; skill :string; } class Person { name: string; skill: string; } let developer: Developer; let person: Person; developer = new Person();
※ 클래스 타입끼리 비교 시에, static member나 constructor는 제외하고 속성만 비교한다.
class Developer { name: string; constructor(name: string, skill: string) { } } class Person { name: string; constructor(age: number) { } } let developer: Developer; let person: Person; developer = person; // O person = developer; // O
※ 함수의 타입 호환
let add = function(a: number) { // ... } let sum = function(a: number, b: number) { // ... } sum = add; // O add = sum; // X
반응형'et cetera > TIL' 카테고리의 다른 글
객체지향 프로그래밍 입문 강의 (1) - 캡슐화 (0) 2021.12.27 클린코드 자바스크립트 강의 (1) (0) 2021.12.27 타입스크립트 강의 내용 정리 (1) (0) 2021.12.22 Javascript Visualized: Promises & async/await (0) 2021.12.04 JavaScript Visualized: Generators and Iterators (0) 2021.11.27