1)
const v2 = {
x: 1 as const,
y: 2
}
{ x: 1; y: number; }
2)
const v3 = {
x: 1,
y: 2,
} as const;
{ readonly x: 1; readonly y: 2; }
const el = document.getElementbyId('foo'); // 타입이 HTMLElement | null
if (typeof el === 'object') {
el; // 타입이 HTMLElement | null
}
답: 자바스크립트에서 typeof null 이 'object' 이기 때문에, if 구문에서 null이 제외되지 않았다.
const jacksonn5 = ['Jackie', 'Tito', 'Jermaine', 'Marlon', 'Michael'];
const memebers = ['Janet', 'Michael'].map(
who => jackson5.find(n => n === who)
).filter(who => who !== undefined); // 타입이 (string | undefined)[]
filter함수를 사용해 undefined를 걸러 내려고 해도 잘 동작 하지 않는다. 이럴때 어떻게 하면 타입을 좁힐 수 있을까? 예시 코드까지 작성하면 좋다~!
(string | undefined) [] => string[] 으로 만들고 싶다!
답: 타입 가드를 사용해서 타입을 좁히자
함수의 반환이 true인 경우, 타입 체커에게 매개변수의 타입을 좁힐 수 있다고 알려준다.
const isDefined<T>(x: T | undefined) x is T {
return x !== undefined;
}
const jacksonn5 = ['Jackie', 'Tito', 'Jermaine', 'Marlon', 'Michael'];
const memebers = ['Janet', 'Michael'].map(
who => jackson5.find(n => n === who)
).filter(isDefined); // 타입이 string[]
interface State {
pageText: string;
isLoading: boolean;
error?: string;
}
// 웹애플리케이션에서 페이지를 선택하면 페이지의 내용을 로드하고 화면에 표시하는 코드
function renderPage(state:State){
if(state.error){
return `Error! Unable to load ${currentPage} : ${state.error}`;
} else if (state.isLoading){
return `Loading ${currentPage}...`;
}
return `<h1>${currentPage}</h1>\n${state.pageText}`
}
// 페이지를 전환하는 함수
async function changePage(state: State, newPage: string){
state.isloading = true;
try {
const response = await fetch(getUrlForPage(newPage));
if(!response.ok){
throw new Error(`Unable to load ${newPage}: ${response.statusText}`);
const text = await response.text();
state.isLoading = false;
state.pageText = text;
}
} catche (e){
state.error = '' + e;
}
}
답:1. State 타입은 isLoading이 true 이면서 동시에 error 값이 설정되는 무효한 상태를 허용한다.
무효한 상태기 존재하면 render()와 chagnePage() 둘 다 제대로 구현할 수 없다.
문제는 상태 값의 두가지 속성이 동시에 정보가 부족하거나(요청이 실패한 것인지 여전히 로딩 중인지 알 수 없다.), 두가지 속성이 충돌(오류 이면서 동시에 로딩중 일 수 있다)할 수 있다는 것이다.
[개선]
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;
request: {[page:string]:RequestState}
}
function renderPage(state: State){
const {currentPage} = state;
const requestState = state.requests[currentPage];
switch (requestState.state){
case: 'pending';
return `Loading ${currentPage}...`;
case: 'error';
return `Error! Unable to load ${currentPage} : ${state.error}`;
case: 'ok';
return `<h1>${currentPage}</h1>\n${state.pageText}`;
}
}
async function chagePage(state: State, newPage:string){
state.requests[newPage] = {state: 'pending'};
state.currentPage = newPage;
try{
const response= await fetch(getUrlForPage(new))
if(!response.ok){
throw new Error(`Unable to load ${newPage}: ${response.statusText}`)
}
const pageText = await resposne.text();
state.requests[newPage] = {state: 'ok', pageText}
}
catch(e) {
state.requests[newPage] = {state: 'error', error:''+ e};
}
}
/**
* 전경색(foreground) 문자열을 반환한다.
* 0 개 또는 1개의 매개변수를 받는다.
* 매개변수가 없을 때는 표준 전경색을 반환한다.
* 매개변수가 있을 때는 특정 페이지의 전경색을 반환한다.
*/
function getForegroundColor(page?:string){
return page === 'login' ? {r: 127, g:127, b:127}: {r:0, g:0, b:0};
}
답: 주석에 타입 정보를 적는것은 피하자. 타입 선언이 중복되는 것으로 끝나면 다행이지만 최악의 경우 타입정보에 모순이 발생한다.
타입 구문은 타입스크립트 타입 체커가 타입 정보를 동기화하도록 강제한다. 주석대신 타입 정보를 작성한다면 코드가 변경된다 하더라도 정보가 정확히 동기화 된다.
개선
/**
애플리케이션 또는 특정 페이지의 전경색을 가져온다.
*/
function getForegroundColor(page?:string){
return page === 'login' ? {r: 127, g:127, b:127}: {r:0, g:0, b:0};
}