티스토리 뷰

TypeScript 


[ 타입스크립트(TypeScript)란 ]

 

TypScript 는 정적 타입 검사자 (TypeScript: A Static Type Checker) 이다. 프로그램을 실행시키지 않으면서 코드의 오류를 검출하는 것을 정적검사 라고 한다. 자바스크립트 코드가 실행(런타임) 중 오류를 발견하는 것과 달리 타입스크립트는 코드 작성(컴파일) 중 오류를 발견해 준다.  아래 예시를 참고하자 ‼️

// 자바스크립트 
// : 오류안남

let age = 25; // 숫자
age = "스물다섯"; // 문자

 

// 타입스크립트
// : 컴파일 오류발생 

let age : number = 25; // 숫자
age = "스물다섯"; // 컴파일 오류 발생(문자열 할당 불가능)

 

 

[ 타입스크립트(TypeScript)는 어떻게 실행될까? ] 

 

 

타입스크립트를 컴파일하면 자바스크립트 코드가 만들어진다. 타입오류가 발생하고 있는 타입스크립트 코드는 컴파일 시 타입 검사를 통과할 수 없기 때문에 자바스크립트 코드로 변환되지 않아 실행할 수 없게 된다. 타입스크립트는 컴파일 결과 타입 검사를 거쳐 자바스크립트 코드로 변환되는데 이때 만약 코드에 오류가 있다면 컴파일 도중 실패하게 되므로 자바스크립트를 보다 더 안전하게 사용하기 위하여 미리 한번 코드를 검사하는 용도로 사용된다고 볼 수 있다. 

 

 

✔︎ TypeScript 컴파일 과정 (.ts 코드에서 .js 코드로의 변환 )

 

① Parsing(구문 분석)

   ❶ TypeScript 코드를 읽고 AST(Abstract Syntax Tree; 코드를 트리 형태로 표현한 자료구조) 로 변환.

② Type Checking (타입 검사)

   ❶ AST를 기반으로 타입을 검사 

   ❷ 타입 오류가 있으면 컴파일 실패.

③ Transformation (변환)

   ❶ AST에서 TypeScript의 타입 정보 제거

   ❷ TypeScript 고유 문법( interface, type, enum 등) 제거

④ Code Generation( JavaScript 코드 생성)

   ❶ AST를 기반으로 최종 JavaScript 코드 생성 

 

 

[ 타입스크립트(TypeScript) 문법 ]

① 정적 타입(Static Typing)

: TypeScript는 변수를 선언할 때 타입을 지정할 수 있다.

let age: number = 25;
age = "twenty-five"; // ❌ 오류: 'string' 형식을 'number'에 할당할 수 없음

 

② 타입 추론(Type Inference)

: TypeScript는 명시적으로 타입을 선언하지 않아도 타입을 추론한다.

let name = "Alice"; // TypeScript는 'name'을 자동으로 'string'으로 추론
name = 10; // ❌ 오류: 'number' 형식을 'string'에 할당할 수 없음

 

③ 인터페이스(Interface)

: 인터페이스를 사용하여 객체의 구조를 정의할 수 있다.

interface User {
  name: string;
  age: number;
  isAdmin?: boolean; // 선택적 속성
}

const user: User = {
  name: "John",
  age: 30
};

console.log(user.name); // ✅ 정상 동작
console.log(user.isAdmin); // ✅ 선택적 속성이므로 undefined 가능

 

④ 제네릭(Generics)

: 제네릭을 사용하면 유연하고 재사용 가능한 코드 작성이 가능하다.

function identity<T>(arg: T): T {
  return arg;
}

console.log(identity<string>("Hello")); // ✅ "Hello"
console.log(identity<number>(123)); // ✅ 123

 

⑤ 유니온 타입(Union Type)

: 하나의 변수에 여러 개의 타입을 허용할 수 있다.

function printId(id: number | string) {
  console.log(`Your ID is: ${id}`);
}

printId(101); // ✅ 정상 동작
printId("abc123"); // ✅ 정상 동작
printId(true); // ❌ 오류: 'boolean'은 허용되지 않음

 

⑥ 타입 가드(Type Guards)

: 타입을 런타임에서 안전하게 구별할 수 있다.

function printLength(value: string | number) {
  if (typeof value === "string") {
    console.log(value.length); // ✅ 문자열일 때만 length 속성 사용 가능
  } else {
    console.log("숫자는 length 속성이 없음");
  }
}

printLength("Hello"); // ✅ 출력: 5
printLength(123); // ✅ 출력: "숫자는 length 속성이 없음"

 

⑦ 열거형(Enum)

: 열거형을 사용하면 명확한 값의 집합을 만들 수 있다. 

(열거형을 사용하면 특정 상태값을 의미 있는 이름으로 관리할 수 있다.) 

enum Status {
  Pending,
  InProgress,
  Done
}

let currentStatus: Status = Status.InProgress;
console.log(currentStatus); // ✅ 출력: 1

 

⑧ 클래스와 상속

: TypeScript는 객체지향 프로그래밍을 지원하며, 클래스와 상속을 사용할 수 있다.

class Animal {
  name: string;

  constructor(name: string) {
    this.name = name;
  }

  makeSound(): void {
    console.log("Some sound...");
  }
}

class Dog extends Animal {
  breed: string;

  constructor(name: string, breed: string) {
    super(name);
    this.breed = breed;
  }

  makeSound(): void {
    console.log("Woof! Woof!");
  }
}

const dog = new Dog("Buddy", "Golden Retriever");
dog.makeSound(); // ✅ "Woof! Woof!"

 

⑨ 타입 별칭 

: 인터페이스와 비슷하지만, 유니온 타입을 포함한 다양한 타입을 정의할 수 있다.(객체, 유니온 타입, 튜플 등)

// UserRole처럼 특정 값만 가질 수 있도록 제약 가능
type UserRole = "admin" | "user" | "guest";

type User = {
  id: number,
  username: string,
  role: UserRole,
};



const user2: User = {
  id: 1,
  username: "Bob",
  role: "admin"
};

 

 


강의 실습 코드

➯ 타입스크립트 참고 강의

 

강의에서 사용되는 예시 실습 코드 1, 2 를 작성해 두었다.

위의 링크를 통해 강의를 확인할 수 있다.

[ TypeScript example  1 ]

// intro to pizza app


type Pizza = {
    id: number,
    name: string,
    price: number
}

type Order = {
    id: number,
    pizza: Pizza,
    status: "ordered" | "completed"
}


let cashInRegister = 100 // 계산대에 있는 현금 
let nextOrderId = 1
let nextPizzaId = 1


const menu : Pizza[] = [
    {id: nextPizzaId++, name: "Margherita", price: 8},
    {id: nextPizzaId++, name: "Pepperoni", price: 10},
    {id: nextPizzaId++, name: "Hawaiian", price: 10},
    {id: nextPizzaId++, name: "Veggie", price: 9}
]


let orderQueue : Order[] = []



function addNewPizza(pizzaObj : Omit<Pizza, "id">) : Pizza {
    const pizza : Pizza = {
        id: nextPizzaId++,
        ...pizzaObj
    }
    menu.push(pizza)
    return pizza
}

addNewPizza({name: "Chicken Bacon Ranch", price: 12})
addNewPizza({name: "BBQ Chicken", price: 12})
addNewPizza({name: "Spicy Sausage", price: 11})

console.log(menu)

function placeOrder(pizzaName: string) : Order | undefined{
    let selectedPizza = menu.find(pizzaObj => pizzaObj.name == pizzaName)
    if(!selectedPizza){
        console.error(`${pizzaName} does not exist in the menu`)
        return
    }
    cashInRegister += selectedPizza.price
    const newOrder : Order = {id: nextOrderId++, pizza: selectedPizza, status : "ordered" }
    orderQueue.push(newOrder)

    return newOrder
}


function addToArray<Type> (array: Type[], item: Type): Type[] | undefined{
    array.push(item)
    return array
}

// example usage:
addToArray<Pizza>(menu, {id: nextPizzaId++, name: "Chicken Bacon Ranch", price: 12})
addToArray<Order>(orderQueue, {id: nextOrderId++, pizza: menu[2], status: "completed"})

console.log(menu)
console.log(orderQueue)

function CompleteOrder(orderId : number) : Order | undefined {
    const order = orderQueue.find(order => order.id == orderId)
    if(!order){
        console.error(`${orderId} was not found in orderQueue`)
        return
    }
    order.status = "completed"

    return order

}


export function getPizzaDetail(identifier: string|number) : Pizza | undefined {
    if(typeof(identifier) === "string"){
        return menu.find(pizza => pizza.name.toLowerCase() === identifier.toLowerCase())
    }else if(typeof(identifier) === "number"){
        return menu.find(pizza => pizza.id === identifier)
    }else{
        throw new TypeError("parameter `identifier` must be either a string or a number")
    }
}





// placeOrder("Chicken Bacon Ranch")
// CompleteOrder(1)

// console.log("Menu", menu)
// console.log("Cash in register", cashInRegister)
// console.log("Order queue", orderQueue)



 // what we learnt
 // 01 basic, literal, and custom types
 // 02 optional properties
 // 03 unions
 // 04 type narrowing
 // 05 utility types
 // 06 generic

[ TypeScript example  2]

type UserRole = "contributor" | "member"| "admin"

type User = {
    id: number,
    username: string,
    role: UserRole

}

// type updatedUser = { // ? : means optional
//     id?: number,
//     username?: string,
//     role?: "contributor" | "member"| "admin"
// }

type updatedUser = Partial<User> // same meaning with the above codes

let userRole : UserRole = "member"


// 위에 선언한 type을 지켜줘야 함. 
// let userRole2: User = {
//     username: "exampleUser",
//     role: "guest"
// };

let nextUser = 1

const users: User[] = [
    {id: nextUser++, username: "john_doe", role: "member"},
    {id: nextUser++, username: "jane_doe", role: "admin"},
    {id: nextUser++, username: "guest_user", role: "contributor"},
    {id: nextUser++, username: "charlie_brown", role: "member"},
]


function updateUser(id: number, updates: updatedUser){
    const foundUser = users.find(user => user.id === id)
    if(!foundUser){
        console.error("USER NOT FOUND")
        return
    }

    // user object.assign to update the found user in place
    Object.assign(foundUser, updates)
}

// omit:  특정 속성만 제거한 타입을 정의
function addNewUser(newUser: Omit<User, "id" | "user">) : User {
    const user: User = {
        id: nextUser++,
        ...newUser //spreaad 
    }

    users.push(user)
    return user

}

// example usage:
addNewUser({username: "joe_schmoe", role:"member"})

// example updates:
// updateUser(1, {username: "new_john_doe"});
// updateUser(4, {role: "contributor"});

console.log(users)

// example updates



function fetchUserDetails(username: string): User{ 
    const user = users.find(user => user.username === username)
    if(!user){
        throw new Error(`user with username ${username} not found`);
    }

    return user
}



// let value : any = 1 // " type : any " means turning off typescript checking
// value = "hi"
// value.map()

// when should i use any? 
// in short: dont


// 개념정리

// utility types
// 01. like a function, they take other types in as a parameter and return a new type. with some changes made to it
// 02. built-in to typescript; perform commonly-needed modifications to existing types
// 03. use "generics" syntax using angle branckets (<>)

// what does the partial type do ?
// this modifies the type you pass in and turns all properties into optional properties

// what does the omit type do ?
// omit takes in a type AND a string(or union of strings)
// property name(s), and returns a new type with those
// properties removed


// Generics
// 01 add flecibility to existing functions, types, etc
// 02 act like function parameters, but for types
// 03 use angle blancket syntax(<>)



const gameScores = [14, 21, 33, 42 ,59]
const favoriteThings = ["raindrops on roses", "whiskers on kittens", "bright copper kettles", "warm woolean mittens"]

const voters = [{name: "Alice", age: 42}, {name:"Bob", age:77}]

function getLastItem<Type>(array: Type[]) : Type | undefined {
    return array[array.length-1]
}

console.log(getLastItem(gameScores))
console.log(getLastItem(favoriteThings))
console.log(getLastItem(voters))



let a = 258
a = "hi"

 

 


Reference

https://ts.winterlood.com/d67c7b28-c191-46ee-9bdc-2ae8643c2028

댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/03   »
1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31
글 보관함