같은 코드를 반복하지 않는 것도 중요하지만, 타입스크립트의 타입에 관한 코드도 예외가 될 수 없다.
아래의 코드는 타입스크립트 타입의 정의에서 발생하는 반복과 그것을 해결하는 타입 연산에 관한 예시이다.
1. 타입 연산을 활용한 타입 관련 코드 중복 제거 기법
a. 인터페이스의 확장으로 중복 줄이기
//name key, age key가 반복됨.
interface Person{
name: string;
age: number;
}
interface PersonSpan {
name: string;
age: number;
job: string;
}
//인터페이스의 확장으로 중복 줄이기
interface PersonBase {
name: string;
age : number;
}
interface PersonWithJob extends PersonBase {
job: string
}
interface PersonWithBirth extends PersonBase {
birth: Date
}
|
b. 중복된 형태의 타입을 타입 엘리어스나 인터페이스를 이용해서 중복 줄이기
//{stock: string, amount: number }가 반복됨
function exchange(a: {ticker: string, amount: number}, b: {ticker: string, amount: number }): {ticker: string, amount: number} {
return {
ticker : a.ticker + '/' + b.ticker,
amount : a.amount + b.amount
}
}
// 타입 엘리어스 선언
type StockExchageInfo = {
ticker: string,
amount: number
}
function exchangeFix(a: StockExchageInfo, b: StockExchageInfo): StockExchageInfo {
return {
ticker : a.ticker + '/' + b.ticker,
amount : a.amount + b.amount
}
}
|
c. 중복된 형태의 함수 타입 시그니처가 공유 되고 있을 때, 함수 시그니처를 타입 엘리어스로 선언하여 중복 줄이기.
//중복된 함수 시그니처로 함수 statement 구현
function max(a: number, b: number): number {
return Math.max(a, b);
}
function min(a: number, b: number): number {
return Math.min(a, b);
}
// 함수 시그니처를 타입으로 정의 후 함수 expression으로 함수 구현
type CompareNum = (a:number, b:number) => number
const max_fix:CompareNum = (a, b) => (Math.max(a, b));
const min_fix:CompareNum = (a, b) => (Math.min(a, b));
|
d. 인터페이스 속성타입 정의시 인덱싱을 사용하여 중복 제거
// 인덱싱을 통한 속성타입의 중복 제거
interface AppStatus {
sesson_token: string;
recent_activity: Date,
contents: string
login_statue : boolean;
}
interface SubAppStatus {
sesson_token: string;
recent_activity: Date,
contents: string
}
interface SubAppStatusFix {
sesson_token: AppStatus['sesson_token'];
recent_activity: AppStatus['recent_activity'];
contents: AppStatus['contents'];
}
//https://www.typescriptlang.org/docs/handbook/utility-types.html (유틸리티 타입의 Pick 항목을 참조)
type SubAppStatusFix2 = {
[k in 'sesson_token' | 'recent_activity' | 'contents']: AppStatus[k]
};
type SubAppStatusFix3 = Pick<AppStatus, 'sesson_token'| 'recent_activity'| 'contents'>;
|
e. 테그된 유니온에서의 중복 제거
interface LoginRequest {
type: 'login'
}
interface LogoutRequest {
type: 'logout'
}
type Requests = LoginRequest | LogoutRequest;
type RequestTypes = 'login' | 'logout' // 이것은 중복에 해당한다.
type RequestTypesFix = Requests['type']; // 중복의 해결 방안: <결과> 'login' | 'logout'
|
c. 속성 이름은 동일한 두 개의 인터페이스(필수 속성, 옵션 속성) 에서의 중복 제거 예시
interface Properties {
uuid: string,
date: Date,
auth: boolean
}
interface PropertiesUpdate {
uuid?: string,
date?: Date,
auth?: boolean
}
type PropertiesUpdateFix = {[k in keyof Properties]?: Properties[k]}; // 중복의 제거
|
d. 값으로 선언된 변수로 부터 타입을 정의 하는 예제
const DEFAULT_PROP = {
a: 1,
b: 2,
c: 'a',
d: 'b'
};
interface Props {
a: number,
b: number,
c: string,
d: string,
};
//자바스크립트 runtime typeof 연산자가 아님
type PropsFix = typeof DEFAULT_PROP;
|
2. 제네릭을 활용한 타입 관련 코드의 중복 제거
제네릭은 타입을 위한 함수로 인식하면 이해하는데 도움이 된다.
함수에서 매개변수로 엉뚱한 인자가 넘어오는 것을 방지하기 위해 타입스크립트 타입 시스템이 이용되는 것 처럼, 타입을 위한 함수인 제네릭도 이와 같은 메커니즘이 적용될 필요가 있다. 이 메커니즘을 적용하기 위해 extends 키워드를 활용할 수 있다.
a. 제네릭의 extends를 이용한 타입 좁히기
type Couple<T extends Name> = [T, T];
const couple: Couple<Name> = [
{first: 'dig', last: 'da'},
{first: 'ff', last: 'gg'}
]; // 정상 (Couple 타입의 제네릭이 Name 인터페이스를 extends 하는 형식이기 때문)
const couple2:Couple<{last: string}> = [
{last: 'ss'},
{last: 'bb'},
];// 제네릭으로 넘긴 인자 '{last:string}'은 'extends Name'에 만족하지 못하는 타입이므로 오류이다.
|
'IT' 카테고리의 다른 글
Effective Typescript - 16 - number 인덱스 시그니처보다는 Array, 튜플, ArrayLike를 사용하기 (0) | 2022.01.21 |
---|---|
Effective Typescript - 15 - 동적 데이터에 인덱스 시그니처 사용하기 (0) | 2022.01.21 |
Effective Typescript - 13 - 타입과 인터페이스의 차이점 이해하기 (0) | 2022.01.20 |
Effective Typescript - 12 - 함수 표현식에 타입 적용하기. (0) | 2022.01.19 |
Node.js와 Browser 에서 실행되는 JS 파일을 공유하고 싶을 때 (0) | 2021.10.23 |