TypeScript
JavaScript의 정적 타입 슈퍼셋. 컴파일 타임에 타입 오류를 잡아 대규모 코드베이스 관리에 유리하다.
기본 타입
// Primitive
let name: string = "김탄"
let age: number = 30
let active: boolean = true
let nothing: null = null
let undef: undefined = undefined
// 배열
let nums: number[] = [1, 2, 3]
let strs: Array<string> = ["a", "b"]
// 튜플
let pair: [string, number] = ["hello", 1]
// any / unknown / never
let x: any = "anything" // 타입 검사 무시 (지양)
let y: unknown = "something" // 사용 전 타입 확인 필요
function error(): never { throw new Error() } // 반환 없음타입 정의
// type alias
type UserId = number
type Status = "active" | "inactive" | "pending" // 유니온
type StringOrNumber = string | number
// interface
interface User {
id: number
name: string
email?: string // 선택적
readonly createdAt: Date // 읽기 전용
}
// interface 확장
interface Admin extends User {
role: "admin" | "superadmin"
}
// type vs interface: 일반적으로 객체 형태는 interface, 나머지는 type제네릭
function identity<T>(value: T): T {
return value
}
// 제약 조건
function getLength<T extends { length: number }>(value: T): number {
return value.length
}
// 제네릭 인터페이스
interface ApiResponse<T> {
data: T
status: number
message: string
}
// 사용
const res: ApiResponse<User[]> = await fetchUsers()유틸리티 타입
interface User {
id: number
name: string
email: string
password: string
}
Partial<User> // 모든 필드 선택적
Required<User> // 모든 필드 필수
Readonly<User> // 모든 필드 읽기 전용
Pick<User, 'id' | 'name'> // 일부 필드만
Omit<User, 'password'> // 일부 필드 제외
Record<string, number> // { [key: string]: number }
Exclude<'a' | 'b' | 'c', 'a'> // 'b' | 'c'
ReturnType<typeof myFn> // 함수 반환 타입
Parameters<typeof myFn> // 함수 매개변수 타입타입 가드
// typeof
function fn(val: string | number) {
if (typeof val === "string") {
val.toUpperCase() // string으로 좁혀짐
}
}
// instanceof
if (error instanceof NetworkError) {}
// in 연산자
if ("email" in user) {}
// 사용자 정의 타입 가드
function isUser(obj: unknown): obj is User {
return typeof obj === "object" && obj !== null && "id" in obj
}클래스
class Service {
private readonly db: Database
constructor(db: Database) {
this.db = db
}
async findById(id: number): Promise<User | null> {
return this.db.query(`SELECT * FROM users WHERE id = ?`, [id])
}
}
// abstract class
abstract class BaseRepository<T> {
abstract findById(id: number): Promise<T | null>
async findOrThrow(id: number): Promise<T> {
const result = await this.findById(id)
if (!result) throw new Error(`Not found: ${id}`)
return result
}
}tsconfig.json 주요 옵션
{
"compilerOptions": {
"target": "ES2022",
"module": "commonjs",
"strict": true,
"noUncheckedIndexedAccess": true,
"noImplicitReturns": true,
"esModuleInterop": true,
"skipLibCheck": true,
"outDir": "./dist",
"rootDir": "./src",
"paths": {
"@/*": ["./src/*"]
}
}
}