lib.dom.d.ts => HTMLElement 를 입력 후 커맨드 클릭 하여 접속// 예제 코드
// <a id="myLink" href="https://google.com"> google </a>
const link1 = document.getElementById('myLink') // link1 = [ HTMLElement | null ] 으로 타입추론
const link2 = document.querySelector('#myLink') // link2 = [ Element | null ] 으로 타입추론
link1.href = "" // link1 오류 : null 값일 수 있음 경고 ,
// href 오류 : 해당 메서드는 AnchorElement 만 가능하지만 현재 link1 은 [ HTMLElement | null ] 으로 타입추론 상태
// [1] if 문 적용 : link1 의 null 값 여부 확인 → 이렇게 적용해도 href에 오류는 그대로 존재
if(link1){
link1.href = ""
}
// [2] 오류 모두 해결 방안
// [ 2-1 ] instanceof 사용 : link1 이 HTMLAnchorElement 타입인지 확인
if(link1 instanceof HTMLAnchorElement){
link1.href = "https://google.ca"
}
// [ 2-2 ] DOM 을 선언할 때부터 as로 타입 단언 해주기
const link11 = document.getElementById('myLink') as HTMLAnchorElement
// 이렇게 바로 사용 가능
link11.href = "https://google.ca"
// [ 이 외 ]
// 📍 createElement
const img = document.createElement('img')
// 이렇게 바로 접근 가능
img.src = ""
// 📍 querySelector
const div = document.querySelector('div');
// 이렇게도 가능 ~!
const buttons = document. querySelectorAll('button');
buttons.forEach(button=>{
button. click();
})
📍 createElement : 매개변수로 HTML의 태그 이름을 전달을 함으로써 그 요소를 찾아서 일치하는 타입이 있으면 그 타입을 반환하되 없을 경우 일반적인 HTMLElement 를 반환
📍 querySelector : div 는 [ HTMLDivElement | null ] 으로 타입 추론 , 역시나 null 값이 포함된 유니온 타입임으로 이 부분은 주의 필요
// <div id="myDiv"></div>
const myDiv = document.getElementById("myDiv");
// (e) : 아무것도 넣지 않으면 자동적으로 MouseEvent 타입으로 추론
// (e: MouseEvent | KeyboardEvent) : 유니언 타입 지정 가능
// (e: Event) : 더 폭 넓게 지정하여 조건문으로 완성
myDiv?.addEventListener('click', (e: Event)=>{
// mouse event
if(e instanceof MouseEvent) {
//로직 구현
const x = e.clientX;
const y = e.clientX;
}
// keyboard event
if(e instanceof KeyboardEvent) {
console.log(e.code);
}
})
• https://developer.mozilla.org/ko/docs/Web/API
• https://developer.mozilla.org/ko/docs/Web/API/HTMLElement
• https://github.com/microsoft/TypeScript/blob/main/src/lib/dom.generated.d.ts
type Id = number | string;
let id: Id = 1;
function getId(id: Id){
if(typeof id === 'number'){
return id
}
return Number(id)
}
getId(1)
getId("2")
typeof 를 사용하여 해당 값의 타입을 확인하여 조건문 설정type Power = "on" | "off"
function power(option: Power) {
if (option === "off"){
console.log("power off")
} else{
console.log("power on")
}
}
power("on")
power("off")
type iOS = { iMessage: ()=> void; }
type android = { message: () => void; }
function sendMessage(os: iOS | android) {
// 예를 들어 os 중에 type iOS 면 iMessage 가 포함된 거니까 true 코드가 실행 돼
if("iMessage" in os) {
os.iMessage(); // 1OS 로 좁혀진다
} else {
os.message(); // android 케이스
}
}
sendMessage ({iMessage: ()=> { console.log("sending iMessage")}}) // ios 타입
sendMessage({message: () => { console.log("sending message")}}) // android 타입
class ApiReponse {
data: any;
}
class ErrorResponse {
message: string;
}
async function handleApiResponse (response: any) {
if(response instanceof ApiReponse) {
// 데이터 처리
} else if (response instanceof ErrorResponse) {
// 에러 처리
}
}
const apiResponse = new ApiReponse;
const errorResponse = new ErrorResponse;
handleApiResponse(apiResponse);
handleApiResponse(errorResponse);
function isErrorReponse(response: ApiReponse | ErrorResponse): response is ErrorResponse {
return (response as ErrorResponse).message !== undefined;
}
const response = { message: "error.." };
if(isErrorReponse (response)) {
// 에러 케이스
console. log (response.message);
}
response is ErrorResponse : true면 response가 ErrorResponse로 타입 좁혀져요! 라는 약속
즉, 이 함수가 true를 리턴하면, response는 ErrorResponse
response as ErrorResponse : 강제로 ErrorResponse처럼 취급해보고 message 속성이 있는지 확인해
만약 message가 있다면 ErrorResponse라고 판단해서 true를 반환
여기서 (response as ErrorResponse)는 response를 임시로 ErrorResponse라고 간주하고, 그 안에 message라는 속성이 존재하는지 확인
이 코드에서는 response 안에 message라는 속성이 있으니까 true
type SuccessResponse = {
type: "success",
data: any;
}
type ErrorResponseType = {
type: "error",
message: string;
}
type ApiResponseType = SuccessResponse | ErrorResponseType;
function handleResponse(response: ApiResponseType) {
if(response.type === "success") {
console.log ('data:', response.data) ;
} else {
console.log (response.message);
}
}
handleResponse({
type: "success",
data: "성공하였습니다"
}) // data: 성공하였습니다
기본 타입을 확장하여 복잡한 타입 관계와 구조를 표현할 수 있게 해주는 다양한 타입 기능
type A = { name: string }
type B = { age: number }
type Person = A & B;
const person: Person = {
name: 'John',
age: 33
}
//-----------------------------------------------------------------------
type UserBase = { id: number };
type WithName = { name: string };
type WithEmail = { email: string };
type WithAge = { age: number };
type GuestUser = UserBase & WithName;
type User = UserBase & WithName & WithEmail & WithAge;
const guest: GuestUser = {
id: 100,
name: "Paul"
}
const user: User = {
id: 123,
name: "Lee" ,
age: 30,
email: "test@email.com"
}
// T 가 extends 를 사용하여 U 를 확장하면 X 아니면 Y
type ConditionalType = T extends U ? X : Y;type IsNumber<T> = T extends number ? "Yes" : "No";
type Result1 = IsNumber<number> // "Yes"
type Result2 = IsNumber<string> // "No"
type JsonOrText<T extends "json" | "text"> = T extends "json" ? object : string;
type JsonResponse = JsonOrText<"json"> // object
type TextReponse = JsonOrText<"text"> // string
type MyObject = {
a: number;
b: string;
c: boolean;
}
type Keys = keyof MyObject; // Keys = "a" | "b" | "c"
// T: 객체 전체 타입 / K: T의 키 중 하나 (K extends keyof T)
// 즉, key는 반드시 obj 안에 존재하는 키만 받을 수 있게 타입 제한
function getProp<T, K extends keyof T>(obj: T, key: K) {
return obj[key];
}
const obj = { x: 10, y: 20, z: 15 };
const value = getProp (obj, "y"); // 20 반환
keyof : Myobject의 key 를 union 타입으로 추출
// type Mapped<T> = {
// [P in keyof T]: T[P]
// }
type OptionalType<T> = {
[P in keyof T]?: T[P]
}
type ReadonlyType<T> = {
readonly [P in keyof T]: T[P]
}
type UserType = {
id: number;
name: string;
age: number;
email: string;
}
// UserType 의 모든 속성을 [ 선택적 ] 으로 변환
// OptionalUserType에 마우스 호버 시 모든 속성 뒤에 ? 붙음
type OptionalUserType = OptionalType<UserType>
// UsenType 의 모든 속성을 [ 읽기 전용 ] 으로 변환
// ReadonLyUserType에 마우스 호버 시 모든 속성 앞에 readonly 붙음
type ReadonLyUserType = ReadonlyType<UserType>
유틸리티 타입 설명
https://www.typescriptlang.org/docs/handbook/utility-types.html
type User = {
id: number;
name: string;
email: string;
}
type PartialUser = Partial<User>
type User1 = {
id: number;
name: string;
}
const user1: Readonly<User1> = {
id: 1,
name: "John"
}
// Readonly 이기 때문에 변경 불가로 오류 발생
user1.id = 10
user1.name = "Amy"
type User2 = {
id: number;
name: string;
email: string;
}
type UserWithNameOnly = Pick<User2, "name">;
// name 값만 선택하여 생성
const User2: UserWithNameOnly = {
name: "lee"
}
type Product = {
id: number;
name: string;
price: number;
uniqueCode: number;
}
// 아래 예제는 여러 개 선택하였지만 하나도 가능 !!
type ProductWithOmit = Omit<Product, 'uniqueCode' | 'price'>;
// [1] 키가 모두 같은 타입
type Country = "South Korea" | "United States" | "Canada";
type Capital = string;
// Country 값이 키값이고, Capital 값 즉 내가 쓰는 string 타입의 값이 키에대한 값이 된다
type CountryCapitals = Record<Country, Capital>;
const capitals: CountryCapitals = {
"South Korea": "Seoul",
"United States": "Washington D.C",
"Canada" : "Ottawa"
}
// [2] 키 값에 대한 타입이 개별적으로 상이할 때
type CountryInfo = {
capital: string;
population: number;
continent: string;
}
type CountryInfoMap = Record<Country, CountryInfo>
const countryInfo: CountryInfoMap = {
'South Korea': {
capital: 'Seoul',
population: 51_000_000,
continent: 'Asia'
},
'United States': {
capital: 'Washington D.C',
population: 331_000_000,
continent: 'North America'
},
'Canada' : {
capital: 'Otat=wa',
population: 83_000_000,
continent: 'North America'
}
}
type SaveUser = (name: string, age: number) => void;
type Params = Parameters<SaveUser>
function saveUser(... params: Params) {
const [ name, age ] = params;
}
saveUser ("David", 33)
• 확장할 수 없는 리터럴 타입의 변수를 생성
• 애플리케이션 전역에 걸쳐 올바른 값 사용을 보장
• 컴파일러의 정확한 타입 추론을 돕는다
const someObject = { } as const
// [객체]
const book = {
title: "TypeScript Guide",
author: "coding moon"
} as const;
// 오류 발생
book.title = "another title";
// [배열]
const nums = [1,2,3,4,5] as const;
// 오류 발생
nums.push(6)
// [실전 예제 1]
const config = {
server: 'https://api.somedomain.com',
port: 8080, version: 2
} as const;
// 오류 발생
config.server = "https: "
// [실전 예제 2] mapping 객체 사용
// 주문 시스템의 상태정보
export const statusCodeMap = {
101: "ordered",
102: "pending",
103: "completed"
} as const;
export type statusCodeKeys = keyof typeof statusCodeMap;
function handleStatus (statusCode: statusCodeKeys) {
// statusCodeMap[102] // 👉 "pending" 값을 가져온다
const message = statusCodeMap[statusCode];
// UI 업데이트 또는 로직처리
}