item 28

interface State { 
	pageText: string;
	isLoading: boolean;
	error?: string; 
}

// 아래와 같이 바꿀 수 있음.   

interface RequestPending { 
			state: 'pending';
}
interface RequestError {
      state: 'error';
			error: string; 
}
interface RequestSuccess { 
			state: 'ok';
			pageText: string;
}

type RequestState = RequestPending | RequestError | RequestSuccess;

interface State {
			currentPage: string;
			requests: {[page: string]: RequestState};
}

item 29

interface CameraOptions { 
			center?: LngLat; 
			zoom?: number; 
			bearing?: number; 
			pitch?: number;
}

// 아래와 같이 바꿀 수 있음.

interface Camera { 
			center: LngLat; 
			zoom: number; 
			bearing: number; 
			pitch: number;
}

interface CameraOptions extends Omit<Partial<Camera>, 'center'> {
      center?: LngLatLike;
}

item 30

item 31

// 버그, 설계 결함이 있는 코드
const extent = (nums: number[]) => {
  let min;
  let max;
  for (const num of nums) {
    if (!min) {
      min = num;
      max = num;
    } else {
      min = Math.min(min, num);
      max = Math.max(max, num); // 이 부분에서 에러
    }
  }
  return [min, max];
};

// min, max가 0인 경우 if문에서 falsy해짐.
// nums 가 빈 배열이라면 [undefined, undefined]를 반환함.

// 개선한 코드

function extent(nums: number[]) {
	let result: [number, number] | null = null; for (const num of nums) {
		if (!result) {
				result = [num, num];
			} else {
				result = [Math.min(num, result[0]), Math.max(num, result[1])];
			} 
	}
	return result; 
}
// 다음과 같이 두 번의 네트워크 요청이 로드되는 동안 user와 posts 속성은 null이 될 수 있음.
async init(userId: string) { return Promise.all([
	async () => this.user = await fetchUser(userId),
	async () => this.posts = await fetchPostsForUser(userId) ]);
}

// 개선한 코드
static async init(userId: string): Promise<UserPosts> { 
					const [user, posts] = await Promise.all([
          fetchUser(userId),
          fetchPostsForUser(userId)
        ]);
	return new UserPosts(user, posts); 
}