가수면
타입 심화 본문
인터섹션 타입
두 개 이상의 타입을 결합하여 새로운 타입을 만들어내 여러 타입을 모두 만족시키는 타입을 의미한다.
예시)
interface IPerson {
name: string;
age: number;
}
interface IEmployee {
company: string;
position: string;
}
type IEmployeePerson = IPerson & IEmployee;
keyof
객체의 키 값들을 숫자나 문자열 리터럴 유니언으로 생성
enum의 경우는 keyof typeof로 사용
type Point = { x: number; y: number };
type P = keyof Point; // “x” | “y”
enum LogLevel {
ERROR, WARN, INFO, DEBUG
}
// 'ERROR' | 'WARN' | 'INFO' | 'DEBUG';
type LogLevelStrings = keyof typeof LogLevel;
추상 클래스
인터페이스와 비슷한 역할.
나머지는 그대로 상속되니 클래스 별로 다르게 지정하고 싶은 속성에 abstract를 부여하면 되는 것 같다.
abstract class Developer {
abstract coding(): void; // 'abstract'가 붙으면 상속 받은 클래스에서 무조건 구현해야 함
drink(): void {
console.log('drink sth');
}
}
class FrontEndDeveloper extends Developer {
coding(): void {
// Developer 클래스를 상속 받은 클래스에서 무조건 정의해야 하는 메서드
console.log('develop web');
}
design(): void {
console.log('design web');
}
}
const dev = new Developer(); // error: cannot create an instance of an abstract class
const josh = new FrontEndDeveloper();
josh.coding(); // develop web
josh.drink(); // drink sth
josh.design(); // design web
제네릭
여러 가지 타입을 유연하게 부여하고 싶을 때 사용할 수 있음.
function getText<T>(text: T): T {
return text;
}
getText<string>('hi');
getText<number>(10);
getText<boolean>(true);
function logText<T, U>(text: T[]): U[] {
console.log(text.length);
return text;
}
유연하게 가져가면서도 특정 속성은 정의하고 싶은 경우
interface LengthWise {
length: number;
}
function logText<T extends LengthWise>(text: T): T {
console.log(text.length);
return text;
}
맵드 타입
기존 타입의 프로퍼티를 변환하거나 조작하여 새로운 타입을 생성할 수 있다.
객체의 프로퍼티 타입을 변환하거나 동일한 타입에 대해서 반복해 선언하는 것을 피할 때 유용함
기본 형태
type MappedType = {
[P in KeyType]: ValueType
}
실사용
보통은 keyof와 많이 씀
type Subset<T> = {
[K in keyof T]?: T[K];
}
type OriginalType = {
name: string;
age: number;
};
type ModifiedType = {
[P in keyof OriginalType]: string;
};
interface UserProfile {
username: string;
email: string;
profilePhotoUrl: string;
}
interface UserProfileUpdate {
username?: string;
email?: string;
profilePhotoUrl?: string;
}
type UserProfileUpdate = {
[p in keyof UserProfile]?: UserProfile[p]
}
Partial
특정 타입의 부분 집합을 만족하는 타입을 정의할 수 있다.
interface Address {
email: string;
address: string;
}
type MayHaveEmail = Partial<Address>;
const me: MayHaveEmail = {}; // 가능
const you: MayHaveEmail = { email: 'test@abc.com' }; // 가능
const all: MayHaveEmail = { email: 'capt@hero.com', address: 'Pangyo' }; // 가능
Pick
특정 타입에서 몇 개의 속성을 선택(pick)하여 타입을 정의할 수 있다.
interface Hero {
name: string;
skill: string;
}
const human: Pick<Hero, 'name'> = {
name: '스킬이 없는 사람',
};
type HasThen<T> = Pick<Promise<T>, 'then' | 'catch'>;
let hasThen: HasThen<number> = Promise.resolve(4);
hasThen.th // 위에서 'then'만 선택하면 'then'만 제공, 'catch' 선택하면 'catch만 제공'
Omit
특정 타입에서 지정된 속성만 제거한 타입을 정의할 수 있다.
interface AddressBook {
name: string;
phone: number;
address: string;
company: string;
}
const phoneBook: Omit<AddressBook, 'address'> = {
name: '재택근무',
phone: 12342223333,
company: '내 방'
}
const chingtao: Omit<AddressBook, 'address'|'company'> = {
name: '중국집',
phone: 44455557777
}
기타 - 타입스크립트 적용 시 팁
타입 지정하지 않은 속성에 대해 추가하거나 검증할 때
마이그레이션 등의 상황 시 images가 undefined거나 지정되지 않은 상황에서 아래 처럼 해당 속성에 대해 검증하거나 추가 할당하려고 할 때 타입 에러가 발생한다.
if (item.images) {
lastImageIndex = index;
}
이 경우 해당 속성이 있는지 'images' in item와 같은 방식으로 검증할 수 있다.
if ('images' in item) {
lastImageIndex = index;
}
둘의 차이는 item.images가 실제 값이 할당되어 있는지(undefined, "" 등 false 반환)를 확인하고, 'images' in item는 해당 속성이 있는지만(값이 undefined, "" 등이어도 해당 속성이 있다면 true 반환) 확인한다.
'JavaScript > TypeScript' 카테고리의 다른 글
event 타입 (0) | 2023.05.08 |
---|---|
ref를 props로 넘겨줄 때 (0) | 2023.04.20 |
넘어오는 데이터가 두 타입 중 하나일 때 (0) | 2023.04.05 |
타입스크립트에서 children (0) | 2023.04.01 |
라이브러리 매개변수 (0) | 2023.03.27 |