제네릭

함수, 클래스, 또는 인터페이스가 다양한 타입에서 동작할 수 있도록 만드는 방법

 

함수

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

 

사용 예시

const numberValue = identity<number>(10);  // number
const stringValue = identity<string>("hello"); // string

// 타입 추론으로 생략 가능
const inferredValue = identity(true); // boolean

클래스

class Box<T> {
  private contents: T;

  constructor(contents: T) {
    this.contents = contents;
  }

  getContents(): T {
    return this.contents;
  }
}

 

사용 예시

const numberBox = new Box<number>(123);
console.log(numberBox.getContents()); // 123

const stringBox = new Box<string>("hello");
console.log(stringBox.getContents()); // "hello"

인터페이스

interface Pair<T, U> {
  first: T;
  second: U;
}

 

사용 예시

const pair: Pair<string, number> = {
  first: "hello",
  second: 42,
};

console.log(pair.first);
console.log(pair.second);

제네릭의 제약 조건

특정 조건을 부여하여, 해당 조건을 만족하는 타입만 사용

 

extends를 사용한 제약 조건

function printLength<T extends { length: number }>(item: T): void {
  console.log(item.length);
}

 

사용 예시

printLength("hello"); // 출력: 5
printLength([1, 2, 3]); // 출력: 3
// printLength(123); // 오류: number에는 length 속성이 없음

 

'TS' 카테고리의 다른 글

열거형 (3)  (0) 2024.12.06
열거형 (2)  (0) 2024.12.05
열거형 (1)  (0) 2024.12.04
클래스 (2)  (0) 2024.12.03
클래스 (1)  (0) 2024.12.02

역방향 매핑

숫자형 열거에서 지원하는 기능
열거형의 키→값 혹은 값→키 접근 가능
문자형은 역방향 매핑이 불가능하다.

enum Colors {
  Red = 0,
  Green = 1,
  Blue = 2,
}

console.log(Colors.Red);    // 0 (키로 값 접근)
console.log(Colors[1]);     // "Green" (값으로 키 접근)
console.log(Colors[2]);     // "Blue"

상수형 열거

직접 값으로 인라인 처리되어 런타임 오버헤드가 없다.
역방향 매핑이 지원되지 않는다.

const enum Days {
  Monday = 1,
  Tuesday,
  Wednesday,
}

const today = Days.Monday;
console.log(today); // 컴파일 시 1로 대체

 

Ambient 열거

declare 키워드를 사용하여 외부에서 정의된 열거형을 타입스크립트에 알려줄 때 사용

declare enum HttpStatus {
  OK = 200,
  NotFound = 404,
  InternalServerError = 500,
}

// 외부 구현체가 제공된다고 가정
console.log(HttpStatus.OK); // 출력: 200 (외부 구현체로 동작)

 

'TS' 카테고리의 다른 글

제네릭  (0) 2024.12.10
열거형 (2)  (0) 2024.12.05
열거형 (1)  (0) 2024.12.04
클래스 (2)  (0) 2024.12.03
클래스 (1)  (0) 2024.12.02

계산된 멤버와 상수 멤버

계산된 멤버

런타임에 값이 계산되는 멤버
복잡한 표현식을 사용할 수 있지만, 다른 멤버의 값에는 영향을 주지 못함

enum FileAccess {
  Read = 1 << 1,             // 계산된 값 (2)
  Write = Read | 1,          // 계산된 값 (3)
  Complex = "FileAccess".length // 문자열 연산 결과 (11)
}

console.log(FileAccess.Write);   // 3
console.log(FileAccess.Complex); // 11

 

상수 멤버

컴파일 타임에 값이 결정되는 멤버로, 단순하고 빠르다

 

초기화된 값: 숫자, 문자열, 다른 상수 열거형 참조
암시적 초기화: 숫자 열거형에서 값 생략 시 자동 증가

enum Status {
  start,          // 0 (암시적 초기화)
  Progress = 1,   // 초기화된 상수
  end = Progress  // 다른 상수 참조
}

console.log(Status.start);    // 0
console.log(Status.end);      // 1

유니온 열거형

열거형 멤버들의 값을 리터럴 타입으로 사용하여 유니온 타입을 정의
열거형의 값이 상수(const) 열거형이어야 함

type Transport =
  | { mode: TrafficMode.Car; speed: number; fuel: number }
  | { mode: TrafficMode.Bike; speed: number; helmet: boolean }
  | { mode: TrafficMode.Bus; speed: number; capacity: number };

function getTransportInfo(transport: Transport): string {
  switch (transport.mode) {
    case TrafficMode.Car:
      return `Car is moving at ${transport.speed} km/h with ${transport.fuel}% fuel.`;
    case TrafficMode.Bike:
      return `Bike is moving at ${transport.speed} km/h. Helmet worn: ${transport.helmet}`;
    case TrafficMode.Bus:
      return `Bus is moving at ${transport.speed} km/h with a capacity of ${transport.capacity} people.`;
    default:
      return "Unknown transport mode.";
  }
}

// Example usage
const carInfo = getTransportInfo({ mode: TrafficMode.Car, speed: 120, fuel: 80 });
console.log(carInfo); // "Car is moving at 120 km/h with 80% fuel."

열거형 멤버 타입

특정 열거형의 멤버들만을 허용하는 타입을 의미

 

enum OrderStatus {
  Pending = "PENDING",
  Shipped = "SHIPPED",
  Delivered = "DELIVERED",
  Canceled = "CANCELED",
}

// 열거형 멤버 타입
type ActiveStatus = OrderStatus.Pending | OrderStatus.Shipped;

// 함수 정의
function updateOrderStatus(status: ActiveStatus): void {
  if (status === OrderStatus.Pending) {
    console.log("Order is still pending.");
  } else if (status === OrderStatus.Shipped) {
    console.log("Order has been shipped.");
  }
}

// 사용 예시
updateOrderStatus(OrderStatus.Pending);  // Valid
updateOrderStatus(OrderStatus.Shipped);  // Valid
// updateOrderStatus(OrderStatus.Delivered); // Error: 'OrderStatus.Delivered' is not assignable

런타임 열거형

런타임에 존재하는 실제 객체

enum Alphabet {
    X, Y, Z
}

function f(obj: { X: number }) {
    return obj.X;
}
f(Alphabet);
// E가 X라는 숫자 프로퍼티를 가지고 있기 때문에 동작하는 코드
console.log(f(Alphabet));

컴파일 열거형

상수 열거형(const enum)을 사용해 생성
컴파일러가 열거형을 상수로 직접 인라인 처리하여 성능을 최적화

const enum State {
  Active = 1,
  Inactive,
  Pending,
}

const nowStatus = State.Active;
console.log(nowStatus); // 컴파일 시 1로 대체

//컴파일 결과(JS코드)
// const nowStatus = 1;
// console.log(nowStatus);

'TS' 카테고리의 다른 글

제네릭  (0) 2024.12.10
열거형 (3)  (0) 2024.12.06
열거형 (1)  (0) 2024.12.04
클래스 (2)  (0) 2024.12.03
클래스 (1)  (0) 2024.12.02

열거형

이름이 있는 상수들의 집합을 정의 

변수 앞에 enum을 붙혀준다.


숫자 열거형

숫자로 이루어진 집합 정의, 초기 미 설정 시 시작은 0으로 시작된다.

enum Direction {
  Up,    // 0
  Down,  // 1
  Left,  // 2
  Right  // 3
}

console.log(Direction.Up);    // 0
console.log(Direction.Right); // 3

// 초기값 지정
enum Status {
  Start = 1, // 1이라는 초기값을 설정
  Process, // 2
  End      // 3
}

console.log(Status.Process); // 2
console.log(Status[1]); // "Start"

문자 열거형

문자로 이루어진 집합의 정의

 

enum Command {
  Up = "UP",
  Down = "DOWN",
  Left = "LEFT",
  Right = "RIGHT",
}

console.log(Command.Up);    // "UP"
console.log(Command.Right); // "RIGHT"

이종 열거형

숫자와 문자열을 혼합해서 사용하는 열거형

enum Mixed {
  No = 0,            // 숫자 값
  Yes = "YES",       // 문자열 값
}

console.log(Mixed.No);  // 0
console.log(Mixed.Yes); // "YES"

'TS' 카테고리의 다른 글

열거형 (3)  (0) 2024.12.06
열거형 (2)  (0) 2024.12.05
클래스 (2)  (0) 2024.12.03
클래스 (1)  (0) 2024.12.02
교차 타입  (0) 2024.11.29

매개변수 프로퍼티

생성자의 매개변수에 접근 제어자(public, private, protected, readonly)를 추가해
클래스의 프로퍼티를 자동으로 선언 및 초기화하는 기능

class Food {
  name: string;
  kcal: number;

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

접근자

객체의 멤버에 대한 접근을 가로채는 방식으로 getters/setters를 지원

class Hero {
  private _name: string;

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

// getter
  public get name(): string {
    return this._name;
  }

// setter
  public set name(newName: string) {
    if (newName.length > 0) {
      this._name = newName;
    } else {
      throw new Error('Name cannot be empty');
    }
  }
}

const hero = new Hero('Iron Man');
console.log(hero.name); // Iron Man
hero.name = 'Spider Man'; // Setter 호출
console.log(hero.name); // Spider Man

전역 프로퍼티

특정 스코프에 속하지 않고 어디서든 접근 가능한 변수를 의미

class MyStaticClass {
  static staticProperty: string = "I am static!";

  static staticMethod() {
    console.log(`Static Property: ${this.staticProperty}`);
  }
}

// Accessing static properties and methods
console.log(MyStaticClass.staticProperty); // "I am static!"
MyStaticClass.staticMethod(); // "Static Property: I am static!"

추상 메서드

abstract 키워드 사용
abstract 키워드로 클래스 또는 메서드를 선언

abstract class Character {
  abstract action(): void; // 추상 메서드 (구현 없음)

  move(): void {
    console.log("Moving...");
  }
}

class Archor extends Character {
  action(): void {
    console.log("attack!");
  }
}

const archor = new Archor();
archor.action(); // "attack!"
archor.move(); // "Moving..."

// const character = new Character(); // 에러: 추상 클래스는 인스턴스화할 수 없습니다.

생성자 함수

클래스의 인스턴스를 초기화하기 위해 호출되는 특수한 메서드
constructor 키워드를 사용하여 정의
객체 생성 시 필요한 초기값을 설정 및 초기 로직을 실행

특징
클래스의 인스턴스 생성 시 자동 호출
단 한 번만 실행되며, 객체 초기화 역할
매개변수를 통해 인스턴스를 생성할 때 필요한 값을 전달받음

class Stone {
  name: string;
  hardness: string;

  constructor(name: string, hardness: string) {
    this.name = name; // 인스턴스 변수 초기화
    this.hardness = hardness;
  }

  StoneInfo(): void {
    console.log(`stone : ${this.name} , hardness : ${this.hardness}.`);
  }
}

const myStone = new Stone("Garnet", "7.0"); // 생성자 호출
myStone.StoneInfo(); // stone : Garnet , hardness : 7.0

 

'TS' 카테고리의 다른 글

열거형 (2)  (0) 2024.12.05
열거형 (1)  (0) 2024.12.04
클래스 (1)  (0) 2024.12.02
교차 타입  (0) 2024.11.29
리터럴 타입  (0) 2024.11.26

클래스

TypeScript 클래스는 객체지향 프로그래밍(OOP)을 지원하기 위해 제공되는 기능

 

기본 선언

class Architecture {
  name: string; // 클래스 속성
  year: number;

  constructor(name: string, year: number) { // 생성자
    this.name = name;
    this.year = year;
  }

  profile(): string { // 메서드
    return ` 건물명 : ${this.name}, 건물년수 : ${this.year} `;
  }
}

// 클래스 사용
const architecture = new Architecture("63빌딩", 39);
console.log(architecture.profile()); // Hello, my name is Alice and I am 30 years old.

console.log(Inheritance);

상속

이미 존재하는 클래스를 확장해 새로운 클래스를 만드는 기능

class Gun {
  constructor(public name: string) {}

  reload(): void {
    console.log(`${this.name}이 장전 되었습니다.`);
  }
}

class gun extends Gun {
  fire(): void {
    console.log(`${this.name}이 발사 되었습니다.`);
  }
}

// 사용 예시
const pistol = new gun("glock");
pistol.reload(); // glock이 장전 되었습니다.
pistol.fire(); // glock이 발사 되었습니다.

접근 제어자

 

1. public

어디서나 접근 가능.
명시적으로 선언하지 않으면 모든 멤버는 기본적으로 public으로 설정(기본 값)

class PublicExample {
    public name: string; // public 생략 가능
    constructor(name: string) {
        this.name = name;
    }
}
const PublicEx = new PublicExample("John");
console.log(PublicEx.name); // 접근 가능

 

2. private
클래스 내부에서만 접근 가능.
클래스 외부나 상속받은 클래스에서도 접근 불가

class PrivateExample {
    private secret: string;
    constructor(secret: string) {
        this.secret = secret;
    }
    getSecret() {
        return this.secret; // 내부에서 접근 가능
    }
}
const PrivateEx = new PrivateExample("hidden");
console.log(PrivateEx.getSecret()); // 접근 가능
// console.log(ex.secret); // 오류: private 속성

 

3. protected

클래스 내부와 상속받은 클래스에서 접근 가능
클래스 외부에서는 접근 불가

class Parent {
    protected value: number;
    constructor(value: number) {
        this.value = value;
    }
}
class Child extends Parent {
    getValue() {
        return this.value; // 상속받은 클래스에서 접근 가능
    }
}
const child = new Child(42);
console.log(child.getValue()); // 접근 가능
// console.log(child.value); // 오류: protected 속성

 

'TS' 카테고리의 다른 글

열거형 (1)  (0) 2024.12.04
클래스 (2)  (0) 2024.12.03
교차 타입  (0) 2024.11.29
리터럴 타입  (0) 2024.11.26
함수(Function)[2]  (0) 2024.11.25

교차 타입

여러 타입을 하나로 결합하여 모든 속성을 동시에 포함하는 새로운 타입을 만드는 방식

& 연산자를 사용

type A = { name: string };
type B = { age: number };

type AB = A & B;

const personal : AB = {
  name: "Alice",
  age: 30,
};


주의
교차 타입은 겹치는 속성이 있을 경우 공통적인 타입으로 좁혀짐
호환되지 않는 타입을 결합하면 오류가 발생

ErrorCase

// type C = { value: string };
// type D = { value: number };

// // 오류 발생: string과 number는 교차 불가
// type CD = C & D;

교차 믹스인

교차 타입을 활용해 여러 객체 또는 클래스의 기능을 결합하는 방식

 

 

1. 객체 교차 믹스인
여러 객체를 하나로 병합하는 방식, Object.assign을 활용

type Flyable = { fly: () => void };
type Swimmable = { swim: () => void };

const flyMixin: Flyable = {
  fly: () => console.log("Flying!"),
};

const swimMixin: Swimmable = {
  swim: () => console.log("Swimming!"),
};

// 교차 타입 생성
const flyingFish: Flyable & Swimmable = Object.assign({}, flyMixin, swimMixin);

flyingFish.fly(); // Flying!
flyingFish.swim(); // Swimming!

 

2. 클래스 교차 믹스인
implements와 교차 타입을 활용하여 여러 동작을 클래스에 포함

type Walkable = {
  walk: () => void;
};

type Runnable = {
  run: () => void;
};

class animal implements Walkable, Runnable {
  walk() {
    console.log("Walking!");
  }

  run() {
    console.log("Running!");
  }
}

const dog = new animal();
dog.walk(); // Walking!
dog.run(); // Running!

 

2-1. 믹스인 함수를 사용한 클래스 병합

type CanEat = {
  eat: () => void;
};

type CanSleep = {
  sleep: () => void;
};

function Eater<TBase extends new (...args: any[]) => {}>(Base: TBase) {
  return class extends Base {
    eat() {
      console.log("Eating!");
    }
  };
}

function Sleeper<TBase extends new (...args: any[]) => {}>(Base: TBase) {
  return class extends Base {
    sleep() {
      console.log("Sleeping!");
    }
  };
}

class Personal {}

const MixedPerson = Sleeper(Eater(Personal));

const human = new MixedPerson();
human.eat(); // Eating!
human.sleep(); // Sleeping!

 

'TS' 카테고리의 다른 글

클래스 (2)  (0) 2024.12.03
클래스 (1)  (0) 2024.12.02
리터럴 타입  (0) 2024.11.26
함수(Function)[2]  (0) 2024.11.25
함수(Function)[1]  (0) 2024.11.20

유니온 타입

하나 이상의 타입을 허용하는 타입
변수, 함수 매개변수, 반환값 등에 대해 서로 다른 여러 타입을 지정

 

기본문법

let val: string | number;

val = "안녕하세요"; // 문자열 허용
val = 123;          // 숫자 허용
// 값 = true;      // 오류: 'boolean'은 허용되지 않음
console.log(val);

공통 필드 유니온

타입을 합칠 때 특정 필드나 속성이 공통적으로 존재하는 경우, 타입 간 관계를 정의하거나 유연한 타입을 생성

 

예시

type traffic= { model: string };
type taxi = traffic & { "hyundai": string };
type bus = traffic & { "kia": string };

type Car = taxi | bus;

 

활용

// 공통 필드로 타입 좁히기
function getCarInfo(car: Car) {
  console.log(`Car model: ${car.model}`); // 공통 필드 사용 가능

  if ('hyundai' in car) {
    console.log(`This is a Taxi. model: ${car.model}`);
  } else if ('kia' in car) {
    console.log(`This is a Bus. model: ${car.model}`);
  }
}

const taxi: Car = { model: "sonata", hyundai: "taxi-model" };
const bus: Car = { model: "granbird", kia: "bus-model" };

getCarInfo(taxi);
getCarInfo(bus);

유니온 구별 

구별하는 기준 : 공통된 속성

type AngleShape =
  | { kind: "circle"; radius: number }
  | { kind: "square"; sideLength: number }
  | { kind: "rectangle"; width: number; height: number };

해당 코드에서는 kind 속성

 

구별 방법

// 1. switch문
function getArea(shape: AngleShape): number {
  switch (shape.kind) {
    case "circle":
          const circleArea = Math.PI * shape.radius ** 2;
          console.log(`Circle Area: ${circleArea}`);
          return circleArea
    case "square":
      return shape.sideLength ** 2;
    case "rectangle":
      return shape.width * shape.height;
    //   efault 케이스의 never 타입: 유니온의 모든 멤버가 처리되었는지 확인하는 역할
    default:
      // TypeScript의 Exhaustiveness 체크
      const _exhaustive: never = shape;
      throw new Error(`Unknown shape: ${_exhaustive}`);
  }
} // 잘못된 멤버가 있을 경우 컴파일 타임에 에러를 발생
getArea({ kind: "circle", radius: 5 });

// 2. if문을 사용한 구별
function getShapeInfo(shape: AngleShape): string {
  if (shape.kind === "circle") {
      const comment = `Circle with radius ${shape.radius}`;
      console.log(comment);
    return comment;
  } else if (shape.kind === "square") {
    return `Square with side length ${shape.sideLength}`;
  } else {
    // 자동으로 rectangle로 좁혀짐
    return `Rectangle with width ${shape.width} and height ${shape.height}`;
  }
}
getShapeInfo({ kind: "circle", radius: 3 });

// 3. in 연산자 사용
function describeShape(shape: AngleShape): string {
    if ("radius" in shape) {
        const message = `Circle with radius ${shape.radius}`;
        console.log(message);
        return message;
  } else if ("sideLength" in shape) {
    return `Square with side length ${shape.sideLength}`;
  } else {
    return `Rectangle with width ${shape.width} and height ${shape.height}`;
  }
}
describeShape({ kind: "circle", radius: 7 });

// 4. 커스텀 정의 타입
function isCircle(shape: AngleShape): shape is { kind: "circle"; radius: number } {
  return shape.kind === "circle";
}

function getCircleInfo(shape: AngleShape): string {
  if (isCircle(shape)) {
    return `Circle with radius ${shape.radius}`;
  }
  return "Not a circle";
}

+ Recent posts