객체(Object)를 생성하는 템플릿 또는 복사기계
// JavaScript (ES6)
class Person {
constructor() {
this.name = 'kim' // 바로 사용 가능
this.age = 20
}
}
// TypeScript (에러 발생)
class Person {
constructor() {
this.name = 'kim' // 에러! Property 'name' does not exist
this.age = 20 // 에러! Property 'age' does not exist
}
}
TypeScript 특징: 속성을 미리 선언해야 함
class Person {
data: number = 0 // 타입 지정 + 기본값
name: string
age: number
}
let john = new Person()
let kim = new Person()
console.log(john.data) // 0
console.log(kim.data) // 0
class Student {
name: string = 'kim'
age: number = 20
married: boolean = false
subjects: string[] = ['math', 'english']
}
class Person {
name: string // 1. 필드값 미리 선언
age: number
constructor(name: string, age: number) { // 2. 매개변수 타입 지정
this.name = name // 3. 필드에 할당
this.age = age
}
}
let person1 = new Person('kim', 25)
let person2 = new Person('park', 30)
this.속성 사용 전 반드시 필드로 선언class Car {
model: string
price: number
constructor(model: string, price: number) {
this.model = model
this.price = price
}
// 메서드 추가
tax(): number {
return this.price * 0.1
}
}
let car1 = new Car('소나타', 3000)
console.log(car1) // { model: '소나타', price: 3000 }
console.log(car1.tax()) // 300
class Calculator {
add(x: number, y: number): number {
return x + y
}
subtract(x: number, y: number): number {
return x - y
}
printResult(result: number): void {
console.log(`결과: ${result}`)
}
}
let calc = new Calculator()
console.log(calc.add(5, 3)) // 8
calc.printResult(calc.add(5, 3)) // 결과: 8
class BankAccount {
private balance: number = 0
deposit(amount: number): void {
this.balance += amount
}
withdraw(amount: number): boolean {
if (this.balance >= amount) {
this.balance -= amount
return true
}
return false
}
getBalance(): number {
return this.balance
}
}
class Word {
num: number[]
str: string[]
constructor(...params: (number | string)[]) {
let 숫자들: number[] = []
let 문자들: string[] = []
params.forEach((param) => {
if (typeof param === 'string') {
문자들.push(param)
} else {
숫자들.push(param)
}
})
this.num = 숫자들
this.str = 문자들
}
}
let obj = new Word('kim', 3, 5, 'park')
console.log(obj.num) // [3, 5]
console.log(obj.str) // ['kim', 'park']
객체의 구조를 정의하는 타입 선언 방식
// Type Alias 방식
type Square1 = {
color: string,
width: number
}
// Interface 방식
interface Square2 {
color: string
width: number
}
let 네모1: Square1 = { color: 'red', width: 100 }
let 네모2: Square2 = { color: 'blue', width: 200 }
공통점: 기능과 용도가 거의 동일
차이점: 확장 방법과 중복 선언 처리가 다름
interface Student {
name: string
}
interface Teacher extends Student {
age: number
}
// Teacher는 name과 age 속성을 모두 가짐
let teacher: Teacher = {
name: 'kim',
age: 30
}
interface Name {
name: string
}
interface Age {
age: number
}
interface Person extends Name, Age {
married: boolean
}
let person: Person = {
name: 'kim',
age: 25,
married: false
}
// Interface - extends 사용
interface Animal {
name: string
}
interface Cat extends Animal {
legs: number
}
// Type - & (intersection) 사용
type Animal2 = {
name: string
}
type Cat2 = Animal2 & { legs: number }
// Interface - 중복 선언 허용 (병합됨)
interface Animal {
name: string
}
interface Animal {
legs: number
}
// Animal = { name: string, legs: number }
// Type - 중복 선언 불가 (에러)
type Animal3 = { name: string }
type Animal3 = { legs: number } // 에러!
| 상황 | 권장 |
|---|---|
| 객체 타입 정의 | Interface |
| 라이브러리 타입 정의 | Interface (확장성) |
| Union 타입 | Type |
| 유틸리티 타입 | Type |
| 엄격한 타입 정의 | Type |
interface MathOperations {
plus: (a: number, b: number) => number
minus: (a: number, b: number) => number
multiply?: (a: number, b: number) => number // 선택적 속성
}
let calculator: MathOperations = {
plus(a, b) {
return a + b
},
minus(a, b) {
return a - b
}
}
interface Product {
product: string
price: number
}
interface CartItem extends Product {
quantity: number
}
let 장바구니: Product[] = [
{ product: '청소기', price: 7000 },
{ product: '삼다수', price: 800 }
]
let 상세장바구니: CartItem[] = [
{ product: '청소기', price: 7000, quantity: 1 },
{ product: '삼다수', price: 800, quantity: 3 }
]
interface BaseProduct {
brand: string
serialNumber: number
model: string[]
}
interface Electronics extends BaseProduct {
warranty: number // 보증기간 (개월)
powerConsumption: number // 전력소비량
}
interface Clothing extends BaseProduct {
size: 'S' | 'M' | 'L' | 'XL'
color: string
}
let tv: Electronics = {
brand: 'Samsung',
serialNumber: 1360,
model: ['TV', 'QLED'],
warranty: 24,
powerConsumption: 120
}
let shirt: Clothing = {
brand: 'Nike',
serialNumber: 5678,
model: ['T-shirt', 'Cotton'],
size: 'M',
color: 'blue'
}
interface Character {
name: string
level: number
hp: number
}
interface Mage extends Character {
mp: number
spells: string[]
castSpell(spellName: string): void
}
interface Warrior extends Character {
armor: number
weapons: string[]
attack(target: string): void
}
class MageCharacter implements Mage {
name: string
level: number = 1
hp: number = 100
mp: number = 50
spells: string[] = ['fireball', 'heal']
constructor(name: string) {
this.name = name
}
castSpell(spellName: string): void {
console.log(`${this.name}이 ${spellName}을 시전합니다!`)
this.mp -= 10
}
}
interface ApiResponse<T> {
success: boolean
data?: T
error?: string
timestamp: number
}
interface User {
id: number
username: string
email: string
}
interface Post {
id: number
title: string
content: string
authorId: number
}
let userResponse: ApiResponse<User> = {
success: true,
data: {
id: 1,
username: 'john_doe',
email: 'john@example.com'
},
timestamp: Date.now()
}
let postsResponse: ApiResponse<Post[]> = {
success: true,
data: [
{ id: 1, title: '첫 글', content: '내용...', authorId: 1 },
{ id: 2, title: '둘째 글', content: '내용...', authorId: 1 }
],
timestamp: Date.now()
}
interface Flyable {
fly(): void
}
interface Swimmable {
swim(): void
}
class Duck implements Flyable, Swimmable {
fly(): void {
console.log('오리가 날아갑니다')
}
swim(): void {
console.log('오리가 수영합니다')
}
}
class Fish implements Swimmable {
swim(): void {
console.log('물고기가 수영합니다')
}
}
interface Shape {
calculateArea(): number
}
abstract class AbstractShape implements Shape {
abstract calculateArea(): number
displayInfo(): void {
console.log(`면적: ${this.calculateArea()}`)
}
}
class Circle extends AbstractShape {
constructor(private radius: number) {
super()
}
calculateArea(): number {
return Math.PI * this.radius ** 2
}
}
class Rectangle extends AbstractShape {
constructor(private width: number, private height: number) {
super()
}
calculateArea(): number {
return this.width * this.height
}
}
// 에러 발생
class Person {
constructor(name: string) {
this.name = name // 에러! Property 'name' does not exist
}
}
// 올바른 방법
class Person {
name: string // 필드 선언 필수
constructor(name: string) {
this.name = name
}
}
// 에러 발생
interface Animal {
name: string
}
interface Dog extends Animal {
name: number // 에러! 타입이 다름
}
// 올바른 방법
interface Animal {
name: string
}
interface Dog extends Animal {
breed: string // 새로운 속성 추가
}
// Interface: 대문자 시작, 명사형
interface UserProfile { }
interface ApiResponse<T> { }
// Class: 대문자 시작, 명사형
class UserManager { }
class DatabaseConnection { }
// Type: 대문자 시작
type StatusType = 'loading' | 'success' | 'error'
// types/user.ts
export interface User {
id: number
name: string
email: string
}
export interface UserCreateRequest {
name: string
email: string
password: string
}
// classes/userManager.ts
import { User, UserCreateRequest } from '../types/user'
export class UserManager {
private users: User[] = []
createUser(request: UserCreateRequest): User {
// 구현...
}
}
interface Repository<T> {
findById(id: number): T | null
save(entity: T): T
delete(id: number): boolean
}
class UserRepository implements Repository<User> {
private users: User[] = []
findById(id: number): User | null {
return this.users.find(user => user.id === id) || null
}
save(user: User): User {
this.users.push(user)
return user
}
delete(id: number): boolean {
const index = this.users.findIndex(user => user.id === id)
if (index > -1) {
this.users.splice(index, 1)
return true
}
return false
}
}