⇒ string은 any와 비슷한 문제를 가지고 있으므로 범위를 제한해서 사용하는 것을 추천한다.
/** string 타입이 남발된 Album 타입 정의 */
interface Album {
artist: string;
title: string;
releaseDate: string; // YYYY-MM-DD 형식으로 들어간다.
recordingType: string; // "live" 혹은 "studio" 값만 들어간다.
};
/** 문제상황 1 */
// releaseDate와 recordingType 형식이 달라도 모두 string 타입이기 때문에 타입 체커 통과
const kindOfBlue: Album = {
artist: 'Mile Davis',
title: 'Kind of Blue',
releaseDate: 'August 17th, 1959', // YYYY-MM-DD 형식이 아니다!
recordingType: 'Studio', // "live" 혹은 "studio" 이외의 값이 들어갔다!
};
/** 문제상황 2 */
// 매개변수 순서가 잘못되어도 둘다 문자열이기 때문에 타입 체커 통과
function recordRelease(title: string, date: string) { /** ... */ }
recordRelease(kindOfBlue.releaseDate, kindOfBlue.title); // 매개변수 순서가 잘못되었다!
type RecordingType = 'studio' | 'live';
interface Album {
artist: string;
title: string;
releaseDate: Date; // Date 객체로 날짜 형식으로 제한
recordingType: RecordingType; // 두 가지의 값만 들어올 수 있도록 제한
}
function getAlbumsOfType (recordingType: string): Album[] { /** ... */ }
/** 이 녹음은 어떤 환경에서 이루어졌는지? */
type RecordingType = "studio" | "live";
interface Album {
artist: string;
title: string;
releaseDate: Date;
recordingType: RecordingType;
}
function getAlbumsOfType(recordingType: RecordingType): void {
console.log(recordingType);
}
🔍keyof 연산자란? 객체 타입에서 객체의 키 값들을 숫자나 문자열 리터럴 타입의 유니온을 생성한다. 즉, 객체 또는 인터페이스의 키 값을 타입으로 반환한다.
/** 언더스코어(Underscore) 라이브러리의 pluck 함수 */
// 어떤 배열에서 특정 하나의 필드 값만 추출하는 함수
function pluck(records, key) {
return records.map(r => r[key]);
}
// 타입을 반영해보자.
function pluck(records: any[], key: string): any[] {
return records.map(r => r[key]);
}
// any 타입은 지양해야하니 제너릭 타입 도입으로 개선해보자.
function pluck<T>(records: T[], key: string): any[] {
return records.map(r => r[key]);
}
// keyof 연산자로 key의 범위를 string보다 더 제한해보자.
// keyof Album -> 타입이 'artist' | 'title' | 'releaseData' | 'recordingType'
function pluck<T>(records: T[], key: keyof T): T[keyof T][] {
return records.map(r => r[key]);
}
(string | Date)[]가 나오는 이유는 Album 타입의 ‘artist’, ‘title’, ‘releaseDate’, ‘recordingType’이 string 혹은 Date 타입이기 때문이에요.
function pluck<T, K extends keyof T>(records: T[], key: K): T[K][] {
return records.map(r => r[key]);
}
// keyof T : T에 속하는 유니온 타입
// K extends : 에서 타입 K를 받아
// T[K][] : 매칭되는 속성의 값 배열만 리턴한다.
훌륭한 글 감사드립니다.