// 지양해야하는 방식 --> 속성 중심
interface StateProps {
a:string;
b:string;
c?:string;
d?:string;
}
interface StateOne {
a:string;
b:string;
}
interface StateTwo {
a:string;
b:string;
c:string;
}
interface StateThree {
a:string;
b:string;
d:string;
}
// 상태 중심
type State = StateOne | StateTwo | StateThree;
@param 구문을 사용하자.// 사용자와 그 사용자의 포럼 게시글을 나타내는 클래스를 가정해보자.
class UserPosts {
user: UserInfo | null;
posts: Post[] | null;
constructor() {
this.user = null;
this.posts = null;
}
async init(userId: string) {
return Promise.all([
async () => this.user = await fetchUser(userId),
async () => this.posts = await fetchPostsUser(userId)
]);
}
getUserName() {
..//?
}
}
두번의 네트워크 요청이 로드되는 동안 user와 posts 속성은 null 상태이다.
어떤 시점에는 둘 다 null이거나, 둘 중 하나만 null이거나, 둘 다 null이 아닐 것이다.
속성 값의 불확실성이 클래스의 모든 메서드에 나쁜 영향을 미친다.
결국 null 체크가 난무하고 버그를 양산하게 된다.
// 사용자와 그 사용자의 포럼 게시글을 나타내는 클래스를 가정해보자.
class UserPosts {
user: UserInfo | null;
posts: Post[] | null;
constructor(user: UserInfo, posts: Post[]) {
this.user = null;
this.posts = null;
}
static async init(userId: string): Promise<UserPosts> {
return Promise.all([
fetchUser(userId),
fetchPostsForUser(userId)
]);
return new UserPosts(user, posts);
}
getUserName() {
return this.user.name;
}
}
이제 UserPosts 클래스는 완전히 null이 아니게 되었고, 메서드를 작성하기 쉬워졌다.
null인 경우가 필요한 속성은 프로미스로 바꾸면 안 된다. 코드가 매우 복잡해지며 모든 메서드가 비동기로 바뀌어야한다. 프로미스는 데이터를 로드하는 코드를 단순하게 만들어 주지만, 데이터를 사용하는 클래스에서는 반대로 코드가 복잡해지는 효과를 내기도 한다.
// 1번
interface Layer {
layout: FillLayout | LineLayout | PointLayout;
paint: FillPaint | LinePaint | PointPaint;
}
// 2번
interface FillLayer {
layout: FillLayout;
paint: FillPaint;
}
interface LineLayer {
layout: LineLayout;
paint: LinePaint;
}
interface PointLayer {
layout: PointLayout;
paint: PointPaint;
}
type Layer = FillLayer | LineLayer | PointLayer;
의미상 1번보다 2번의 정의가 맞을때, 이러한 패턴을 태그된 유니온(또는 구분된 유니온)이라고 말한다.
interface FillLayer {
type: 'fill';
...
}
interface LineLayer {
type: 'line';
...
}
interface PointLayer {
type: 'paint';
...
}
type Layer = FillLayer | LineLayer | PointLayer;
interface Person {
name: string;
// place와 date가 둘 다 동시에 있거나 동시에 없을 때, 하나의 객체로 모아서 설계
birth?: {
place: string;
date: Date;
}
}
타입 구조에 손대지 못할 때도 인터페이스 유니온을 사용해서 속성간의 관계를 정의해줄 수 있다.
interface Name {
name: string;
}
interface PersonWithBirth extends Name {
placeOfBirth: string;
dateOfBirth: Date;
}
type Person = Name | PersonWithBirth;
type RecordingType = 'studio' | 'live';
interface Album {
artist: string;
title: string;
releaseDate: Date;
recordingType: RecordingType;
}