# ๐ Item29 ~ 33
# Item29. ์ฌ์ฉํ ๋๋ ๋๊ทธ๋ฝ๊ฒ, ์์ฑํ ๋๋ ์๊ฒฉํ๊ฒ
- ํจ์์ ๋งค๊ฐ๋ณ์๋ ํ์ ์ ๋ฒ์๊ฐ ๋์ด๋ ๋์ง๋ง, ๊ฒฐ๊ณผ๋ฅผ ๋ฐํํ ๋๋ ์ผ๋ฐ์ ์ผ๋ก ํ์ ์ ๋ฒ์๊ฐ ๋ ๊ตฌ์ฒด์ ์ด์ด์ผ ํ๋ค.
- ์์) 3D ๋งคํ API - ์นด๋ฉ๋ผ์ ์์น๋ฅผ ์ง์ ํ๊ณ ๊ฒฝ๊ณ ๋ฐ์ค์ ๋ทฐํฌํธ๋ฅผ ๊ณ์ฐ
# โญ๏ธ ์ฌ์ฉํ ๋๋ ๋๊ทธ๋ฝ๊ฒ
declare function setCamera(camera: CameraOptions): void;
declare function viewportForBounds(bounds: LngLatBounds): CameraOptions;
- ์ผ๋ถ ๊ฐ์ ๊ฑด๋๋ฆฌ์ง ์์ผ๋ฉด์ ๋์์ ๋ค๋ฅธ ๊ฐ์ ์ค์ ํ ์ ์์ด์ผ ํ๋ฏ๋ก
CameraOptions
์ ํ๋๋ ๋ชจ๋ ์ ํ์ ์ด๋ค. - ๊ฒ๋ค๊ฐ
LngLat
ํ์ ๋ ๋ค์ํ ํํ ์ ๋งค๊ฐ๋ณ์ ํ์ ์ ์ ์ํ์ฌ ํธ์์ฑ์ ์ ๊ณตํ์ฌ ํจ์ ํธ์ถ์ ์ฝ๊ฒ ํ ์ ์๋ค.
interface CameraOptions {
center?: LngLat;
zoom?: number;
bearing?: number;
pitch?: number;
}
type LngLat = { lgn: number; lat: number; } | { lon: number; lat: number; } | [number, number];
- ๋ํ
viewportForBounds
ํจ์๋ ์์ ๊ฐ์ ์์ ๋ก์ด ํ์ ์ ๋งค๊ฐ๋ณ์๋ก ๋ฐ๋๋ค.LngLat
ํ์ ๊ณผ ์กฐํฉํ๋ฉดLngLatBounds
์ ๊ฐ๋ฅํ ํํ๋ 19๊ฐ์ง ์ด์์ผ๋ก ๋งค์ฐ ์์ ๋ก์ด ํ์ ์ด๋ค.
type LngLatBounds = { northeast: LngLat, southwest: LngLat } | [LngLat, LngLat] | [number, number, number, number];
# โญ๏ธ ์์ฑํ ๋๋ ์๊ฒฉํ๊ฒ
function focusOndFeature(f: Feature) {
const bounds = calculateBoundingBox(f);
const camera = viewportForBounds(bounds);
setCamera(camera);
const { center: { lat, lng }, zoom } = camera;
// ~~~ ... ํ์์ 'lat' ์์ฑ์ด ์์ต๋๋ค.
// ~~~ ... ํ์์ 'lng' ์์ฑ์ด ์์ต๋๋ค.
zoom; // ํ์
์ด number | undefined
window.location.search = `?v=@${lat},${lng}z${zoom}`;
}
์ ์ค๋ฅ๋
lat
,lng
์์ฑ์ด ์๊ณzoom
์์ฑ๋ง ์กด์ฌํ์ฌ ๋ฐ์ํ๊ณ ,zoom
์ ํ์ ์ดnumber | undefined
๋ก ์ถ๋ก ๋๋ ๊ฒ๋ ์ญ์ ๋ฌธ์ ๋ค.๊ทผ๋ณธ์ ์ธ ๋ฌธ์ ๋
viewportForBounds
์ ํ์ ์ ์ธ์ด ์ฌ์ฉ๋ ๋๋ฟ๋ง ์๋๋ผ ๋ง๋ค์ด์ง ๋๋ ๋๋ฌด ์์ ๋กญ๋ค๋ ๊ฒ์ด๋ค.camera
๊ฐ์ ์์ ํ ํ์ ์ผ๋ก ์ฌ์ฉํ๋ ์ ์ผํ ๋ฐฉ๋ฒ์ ์ ๋์จ ํ์ ์ ๊ฐ ์์๋ณ๋ก ์ฝ๋๋ฅผ ๋ถ๊ธฐํ๋ ๊ฒ์ด๋ค.์ ๋์จ ํ์ ์ ์์๋ณ ๋ถ๊ธฐ๋ฅผ ์ํ ๋ฐฉ๋ฒ์ ์ขํ๋ฅผ ์ํ ๊ธฐ๋ณธ ํ์์ ๊ตฌ๋ถํ๋ ๊ฒ์ด๋ค.
- ๋ฐฐ์ด๊ณผ ๋ฐฐ์ด ๊ฐ์ ๊ฒ์ ๊ตฌ๋ถ์ ์ํด
LngLat
์LngLatLike
๋ฅผ ๊ตฌ๋ถํ ์ ์๋ค. - ๋ํ
setCamera
ํจ์๊ฐ ๋งค๊ฐ๋ณ์๋ก ๋ฐ์ ์ ์๋๋ก, ์์ ํ๊ฒ ์ ์๋Camera
ํ์ ๊ณผCamera
ํ์ ์ด ๋ถ๋ถ์ ์ผ๋ก ์ ์๋ ๋ฒ์ ์ ๊ตฌ๋ถํ ์๋ ์๋ค.
- ๋ฐฐ์ด๊ณผ ๋ฐฐ์ด ๊ฐ์ ๊ฒ์ ๊ตฌ๋ถ์ ์ํด
interface LngLat {
lng: number;
lat: number;
}
type LngLatLike = LngLat | { lon: number; lat: number; } | [number, number];
interface Camera {
center: LngLat;
zoom: number;
bearing: number;
pitch: number;
}
interface CameraOptions extends Omit<Partial<Camera>, 'center'> {
center?: LngLatLike;
}
type LngLatBounds = { northeast: LngLatLike, southwest: LngLatLike } | [LngLatLike, LngLatLike] | [number, number, number, number];
declare function setCamera(camera: CameraOptions): void;
declare function viewportForBounds(bounds: LngLatBounds): Camera;
# Item30. ๋ฌธ์์ ํ์ ์ ๋ณด๋ฅผ ์ฐ์ง ์๊ธฐ
- ํ์
์คํฌ๋ฆฝํธ์ ํ์
๊ตฌ๋ฌธ ์์คํ
์ ๊ฐ๊ฒฐํ๊ณ , ๊ตฌ์ฒด์ ์ด๋ฉฐ, ์ฝ๊ฒ ์ฝ์ ์ ์๋๋ก ์ค๊ณ๋์ด์๋ค.
- ํจ์์ ์ ๋ ฅ๊ณผ ์ถ๋ ฅ์ ํ์ ์ ์ฝ๋๋ก ํํํ๋ ๊ฒ์ด ์ฃผ์๋ณด๋ค ๋ ๋์ ๋ฐฉ๋ฒ์ด๋ผ๋ ๊ฒ์ ์๋ช ํ๋ค.
- ๋๊ตฐ๊ฐ ๊ฐ์ ํ์ง ์๋ ์ด์ ์ฃผ์ใ
์ ์ฝ๋์ ๋๊ธฐํ๋์ง ์๋๋ค.
- ์ฃผ์ ๋์ ํ์ ์ ๋ณด๋ฅผ ์์ฑํ๋ค๋ฉด ์ฝ๋๊ฐ ๋ณ๊ฒฝ๋๋ค ํ๋๋ผ๋ ์ ๋ณด๊ฐ ์ ํํ ๋๊ธฐํ๋๋ค.
- ํน์ ๋งค๊ฐ๋ณ์๋ฅผ ์ค๋ช
ํ๊ณ ์ถ๋ค๋ฉด JSDoc์
@param
๊ตฌ๋ฌธ์ ์ฌ์ฉํ๋ฉด ๋๋ค. - ๊ฐ์ ๋ณ๊ฒฝํ์ง ์๋๋ค๊ณ ์ค๋ช
ํ๋ ์ฃผ์๋ ์ข์ง ์๋ค.
- ๋ํ ๋งค๊ฐ๋ณ์๋ฅด ๋ณ๊ฒฝํ์ง ์๋๋ค๋ ์ฃผ์๋ ์ฌ์ฉํ์ง ์๋ ๊ฒ์ด ์ข๋ค.
- ๊ทธ ๋์ ,
readonly
๋ก ์ ์ธํ์ฌ ํ์ ์คํฌ๋ฆฝํธ๊ฐ ๊ท์น์ ๊ฐ์ ํ ์ ์๊ฒ ํ๋ฉด ๋๋ค.
- ๋ณ์๋ช
์ ํ์
์ ๋ณด๋ฅผ ๋ฃ์ง ์๋๋ก ํ๋ค.
- ์๋ฅผ ๋ค์ด ๋ณ์๋ช
ageNum
์ผ๋ก ํ๋ ๊ฒ๋ณด๋ค๋age
๋ก ํ๊ณ , ๊ทธ ํ์ ์ดnumber
์์ ๋ช ์ํ๋๊ฒ ์ข๋ค. - ๊ทธ๋ฌ๋ ๋จ์๊ฐ ์๋ ์ซ์๋ค์ ์์ธ์ด๋ค. ๋จ์๊ฐ ๋ฌด์์ธ์ง ํ์คํ์ง ์๋ค๋ฉด ๋ณ์๋ช ๋๋ ์์ฑ ์ด๋ฆ์ ๋จ์๋ฅผ ํฌํจํ ์ ์๋ค.
- ์๋ฅผ ๋ค์ด ๋ณ์๋ช
- ์ฃผ์๊ณผ ๋ณ์๋ช
์ ํ์
์ ๋ณด๋ฅผ ์ ๋ ๊ฒ์ ํผํด์ผ ํ๋ค.
- ํ์ ์ ์ธ์ด ์ค๋ณต๋๋ ๊ฒ์ผ๋ก ๋๋๋ฉด ๋คํ์ด์ง๋ง ์ต์ ์ ๊ฒฝ์ฐ๋ ํ์ ์ ๋ณด์ ๋ชจ์์ด ๋ฐ์ํ๊ฒ ๋๋ค.
- ํ์
์ด ๋ช
ํํ์ง ์์ ๊ฒฝ์ฐ๋ ๋ณ์๋ช
์ ๋จ์ ์ ๋ณด๋ฅผ ํฌํจํ๋ ๊ฒ์ ๊ณ ๋ คํ๋ ๊ฒ์ด ์ข๋ค. (์๋ฅผ ๋๋ฌ
timeMs
๋๋temperatureC
)
# Item31. ํ์
์ฃผ๋ณ์ null
๊ฐ ๋ฐฐ์นํ๊ธฐ
# โญ๏ธ ์์1 . ์ซ์๋ค์ ์ต์๊ฐ๊ณผ ์ต๋๊ฐ ๊ณ์ฐ
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;
}
// 1) non-null assertion
const [min, max] = extent([0, 1, 2])!;
const span = max - min; // ์ ์
// 2) if ๊ตฌ๋ฌธ์ผ๋ก null check
const range = extent([0, 1, 2]);
if (range) {
const [min, max] = range;
const span = max - min; // ์ ์
}
# โญ๏ธ ์์2. ์ฌ์ฉ์์ ํฌ๋ผ ๊ฒ์๊ธ์ ๋ํ๋ด๋ ํด๋์ค
- ์๋์ ๊ฐ์ด
init
๋ฉ์๋๋ฅผ ๊ตฌ์ฑํ๋ฉดnull
์ ์กด์ฌ ์ ๋ฌด์ ๋ฐ๋ผ ๋ค ๊ฐ์ง ์ํ๊ฐ ์กด์ฌํ์ฌnull
์ฒดํฌ๊ฐ ๋๋ฌดํ๊ณ ๋ฒ๊ทธ๋ฅผ ์์ฐํ๊ฒ ๋๋ค.
class UserPosts {
user: UserInfo | null;
posts: Post[] | null;
constructor() {
this.user = null;
this.posts = null;
}
async init(userId: string) {
return Promise.all([
async () => this.users = await fetchUser(userId),
async () => this.posts = await fetchPostsForUser(userId)
]);
}
getUserName() {}
}
- ํ์ํ ๋ฐ์ดํฐ๊ฐ ๋ชจ๋ ์ค๋น๋ ํ์ ํด๋์ค๋ฅผ ๋ง๋ค๋๋ก ๋ฐ๊ฟ๋ณด์.
class UserPosts {
user: UserInfo;
posts: Post[];
constructor(user: UserInfo, posts: Posts[]) {
this.user = user;
this.posts = posts;
}
static async init(userId: string): Promise<UserPosts> {
const [user, posts] = await Promise.all([
fetchUser(userId),
fetchPostsForUser(userId)
]);
return new UserPosts(user, posts);
}
getUserName() {
return this.user.name;
}
}
# ๐ก ๊ฒฐ๋ก
- ํ ๊ฐ์
null
์ฌ๋ถ๊ฐ ๋ค๋ฅธ ๊ฐ์null
์ฌ๋ถ์ ์์์ ์ผ๋ก ๊ด๋ จ๋๋๋ก ์ค๊ณํ๋ฉด ์ ๋๋ค. - API ์์ฑ ์์๋ ๋ฐํ ํ์
์ ํฐ ๊ฐ์ฒด๋ก ๋ง๋ค๊ณ ๋ฐํ ํ์
์ ์ฒด๊ฐ
null
์ด๊ฑฐ๋null
์ด ์๋๊ฒ ๋ง๋ค์ด์ผ ํ๋ค. - ํด๋์ค๋ฅผ ๋ง๋ค ๋๋ ํ์ํ ๋ชจ๋ ๊ฐ์ด ์ค๋น๋์์ ๋ ์์ฑํ์ฌ
null
์ด ์กด์ฌํ์ง ์๋๋ก ํ๋ ๊ฒ์ด ์ข๋ค. strictNullChecks
๋ฅผ ์ค์ ํ๋ฉด ์ฝ๋์ ๋ง์ ์ค๋ฅ๊ฐ ํ์๋๊ฒ ์ง๋ง,null
๊ฐ๊ณผ ๊ด๋ จ๋ ๋ฌธ์ ์ ์ ์ฐพ์๋ผ ์ ์๊ธฐ ๋๋ฌธ์ ๋ฐ๋์ ํ์ํ๋ค.
# Item32. ์ ๋์จ์ ์ธํฐํ์ด์ค๋ณด๋ค๋ ์ธํฐํ์ด์ค์ ์ ๋์จ์ ์ฌ์ฉํ๊ธฐ
- ํ๊ทธ๋ ์ ๋์จ์์ ์ธํฐํ์ด์ค์ ์ ๋์จ ํจํด ์ ์ฉํ๊ธฐ
interface FillLayer {
type: 'fill';
layout: FillLayout;
paint: FillPaint;
}
interface LineLayer {
type: 'line';
layout: LineLayout;
paint: LinePaint;
}
type Layer = FillLayer | LineLayer;
type
์์ฑ์ 'ํ๊ทธ' ์ด๋ฉฐ ๋ฐํ์์ ์ด๋ค ํ์ ์Layer
๊ฐ ์ฌ์ฉ๋๋์ง ํ๋จํ๋ ๋ฐ ์ฐ์ธ๋ค.- ํ์
์คํฌ๋ฆฝํธ๋ ํ๊ทธ๋ฅผ ์ฐธ๊ณ ํ์ฌ
Layer
์ ํ์ ์ ๋ฒ์๋ฅผ ์ขํ ์๋ ์๋ค.
- ํ์
์คํฌ๋ฆฝํธ๋ ํ๊ทธ๋ฅผ ์ฐธ๊ณ ํ์ฌ
function drawLayer(layer: Layer) {
if (layer.type === 'fill') {
const { paint } = layer; // ํ์
์ด FillPaint
const { layout } = layer; // ํ์
์ด FillLayout
} else {
const { paint } = layer; // ํ์
์ด LinePaint
const { layout } = layer; // ํ์
์ด LineLayout
}
}
- ํ์ ์ ๊ตฌ์กฐ๋ฅผ ์ ๋ ์ ์๋ ์ํฉ์์๋ ์ด ๊ธฐ๋ฒ์ ์ด์ฉํด์ ์์ฑ ์ฌ์ด์ ๊ด๊ณ๋ฅผ ๋ชจ๋ธ๋งํ ์ ์๋ค.
interface Name {
name: string;
}
interface PersonWithBirth extends Name {
placeOfBirth: string;
dateOfBirth: Date;
}
type Person = Name | PersonWithBirth;
function eulogize(p: Person) {
if ('placeOfBirth' of p) {
p; // ํ์
์ด PersonWithBirth
const { dateOfBirth } = p; // ์ ์, ํ์
์ด Date
}
}
- ๋๋ ๋ ๊ฐ์ ์ต์ ๋ํ ์์ฑ์ ํ๋์ ๊ฐ์ฒด๋ก ๋ชจ์์ ์ค๊ณํ ์๋ ์๋ค.
interface Person {
name: string;
birth?: {
place: string;
date: Date;s
}
}
# Item33. string
ํ์
๋ณด๋ค ๋ ๊ตฌ์ฒด์ ์ธ ํ์
์ฌ์ฉํ๊ธฐ
type RecordingType = 'studio' | 'live';
interface Album {
artist: string;
title: string;
releaseDate: Date;
recordingTpye: RecordingType;
}
const kindOfBlue: Album = {
artist: 'Miles Davis',
title: 'Kind of Blue',
releaseDate: new Date('1959-08-17'),
recordingType: 'Studio', // '"Studio"' ํ์์ 'RecordingType' ํ์์ ํ ๋นํ ์ ์์ต๋๋ค.
}
string
ํ์ ๋ณด๋ค ๋ ๊ตฌ์ฒด์ ์ธ ํ์ ์ ์ฌ์ฉํ์ ๋์ ์ฅ์ - ํ์ ์ ๋ช ์์ ์ผ๋ก ์ ์ํจ์ผ๋ก์จ ๋ค๋ฅธ ๊ณณ์ผ๋ก ๊ฐ์ด ์ ๋ฌ๋์ด๋ ํ์ ์ ๋ณด๊ฐ ์ ์ง๋๋ค.
- ํ์ ์ ๋ช ์์ ์ผ๋ก ์ ์ํ๊ณ ํด๋น ํ์ ์ ์๋ฏธ๋ฅผ ์ค๋ช ํ๋ ์ฃผ์์ ๋ถ์ฌ ๋ฃ์ ์ ์๋ค.
keyof
์ฐ์ฐ์๋ก ๋์ฑ ์ธ๋ฐํ๊ฒ ๊ฐ์ฒด์ ์์ฑ ์ฒดํฌ๊ฐ ๊ฐ๋ฅํด์ง๋ค.
# โญ๏ธ keyof
์ฐ์ฐ์
- ์ฐ์ ์์๋ก underscore์
pluck
ํจ์๋ฅผ ์ดํด๋ณด์
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]); // ~~~ '{}' ํ์์ ์ธ๋ฑ์ค ์๊ทธ๋์ฒ๊ฐ ์์ผ๋ฏ๋ก ์์์ ์์์ ์ผ๋ก 'any' ํ์์ด ์์ต๋๋ค.
}
key
์ ํ์ ์ดstring
์ด์ฌ์ ๋ฒ์๊ฐ ๋๋ค๋ ์ค๋ฅ๋ฅผ ๋ฐ์์ํจ๋ค.- ๊ทธ๋์
keyof
์ฐ์ฐ์๋ฅผ ์ด์ฉํด์ ์ ํจํ ๊ฐ์ ์ง์ ํด๋ณด์.
type K = keyof Album; // ํ์
์ด "artist" | "title" | "releaseDate" | "recordingType"
// T[keyof T]๋ T ๊ฐ์ฒด ๋ด์ ๊ฐ๋ฅํ ๋ชจ๋ ๊ฐ์ ํ์
์ด๋ค.ใด
function pluck<T>(records: T[], key: keyof T): T[keyof T][] {
return records.map(r => r[key]);
}
- ํ์ง๋ง ์๋์ ๊ฐ์ ๊ฒฝ์ฐ
key
์ ๊ฐ์ผ๋ก ํ๋์ ๋ฌธ์์ด์ ๋ฃ๊ฒ ๋๋ฉด, ๊ทธ ๋ฒ์๊ฐ ๋๋ฌด ๋์ด์ ์ ์ ํ ํ์ ์ด๋ผ๊ณ ๋ณด๊ธฐ ์ด๋ ค์ด ๊ฒฝ์ฐ๋ ์๋ค.
const releaseDates = pluck(albums, 'releaseDate'); // ํ์
์ด (string | Date)[]
- ๋ฒ์๋ฅผ ๋ ์ขํ๊ธฐ ์ํด,
keyof T
์ ๋ถ๋ถ ์งํฉ์ผ๋ก ๋ ๋ฒ์งธ ์ ๋ค๋ฆญ ๋งค๊ฐ๋ณ์๋ฅผ ๋์ ํด์ผ ํ๋ค.
function pluck<T, K extends keyof T>(records: T[], key: K): T[K][] {
return records.map(r => r[key]);
}
pluck(albums, 'releaseDate'); // ํ์
์ด Date[]
pluck(albums, 'artist'); // ํ์
์ด string[]
pluck(albums, 'recordingType'); // ํ์
์ด RecordingType[]
pluck(albums, 'recordingDate'); // ~~~ '"recordingDate"' ํ์์ ์ธ์๋ ... ํ์์ ๋งค๊ฐ๋ณ์์ ํ ๋น๋ ์ ์์ต๋๋ค.
# ๐ก ๊ฒฐ๋ก
string
์any
์ ๋น์ทํ ๋ฌธ์ ๋ฅผ ๊ฐ์ง๊ณ ์๋ค.- ๋ฐ๋ผ์ ์๋ชป ์ฌ์ฉํ๊ฒ ๋๋ฉด ๋ฌดํจํ ๊ฐ์ ํ์ฉํ๊ณ ํ์ ๊ฐ์ ๊ด๊ณ๋ ๊ฐ์ถ์ด ๋ฒ๋ฆฐ๋ค.
- ์ด๋ฌํ ๋ฌธ์ ์ ์ ํ์ ์ฒด์ปค๋ฅผ ๋ฐฉํดํ๊ณ ์ค์ ๋ฒ๊ทธ๋ฅผ ์ฐพ์ง ๋ชปํ๊ฒ ๋ง๋ ๋ค.
- ๋ณ์์ ๋ฒ์๋ฅผ ๋ณด๋ค ์ ํํ๊ฒ ํํํ๊ณ ์ถ๋ค๋ฉด
string
ํ์ ๋ณด๋ค๋ ๋ฌธ์์ด ๋ฆฌํฐ๋ด ํ์ ์ ์ ๋์จ์ ์ฌ์ฉํ๋ฉด ๋๋ค.- ํ์ ์ฒดํฌ๋ฅผ ๋ ์๊ฒฉํ ํ ์ ์๊ณ ์์ฐ์ฑ์ ํฅ์์ํฌ ์ ์๋ค.
- ๊ฐ์ฒด์ ์์ฑ ์ด๋ฆ์ ํจ์ ๋งค๊ฐ๋ณ์๋ก ๋ฐ์ ๋๋
string
๋ณด๋ค๋keyof T
๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ด ์ข๋ค.