tsc !== 타입 스크립트 컴파일러

tsc와 타입스크립트 컴파일러는 다른 내용이다. tsc= 컴파일러 명령어 인터페이스 CLI (command- line interface이다.)

후자는 TypeScript언어로 작성된 코드를 js코드로 변환해주는 도구.

 


.d.ts. 파일의 역할과 사용 방법

  • TypeScript의 타입 선언 파일(Declaration File)
  • d.ts 파일이 제공되지 않는 경우 직접 작성
  • 타입 정보를 .d.ts 파일로 작성하여 타입 체크를 보다 엄격하게 하거나 개발 생산성을 향상

 

 

 

 

 


 

TypeScript에서 지원하는 기본 타입

void: 반환 값이 없는 함수의 반환 타입

function sayHello(): void {
    console.log("Hello!");
}

 

 


가변적 데이터 타입

- any 타입

let dynamicValue: any = "Hello";
dynamicValue = 42; // 가능
dynamicValue = true; // 가능

- unknown 타입

let dynamicValue: unknown = "Hello";
dynamicValue = 42; // 가능
dynamicValue = true; // 가능

// 명시적인 타입 확인 필요
if (typeof dynamicValue === "string") {
    console.log(dynamicValue.length); // 가능
}

- union 타입

let data: string | number = "Hello";
data = 42; // 가능
data = true; // 오류: 'boolean' 타입은 'string | number' 타입에 할당할 수 없음

// 타입 가드를 활용하여 가변적인 동작 구현
function process(data: string | number) {
    if (typeof data === "string") {
        // data가 문자열인 경우의 처리
        console.log(data.toUpperCase());
    } else {
        // data가 숫자인 경우의 처리
        console.log(data.toFixed(2));
    }
}

 


유틸리티 타입

1. Partial<T>

  • Partial<T>는 제네릭 타입 T의 모든 속성을 선택적(optional)으로 만드는 유틸리티 타입입니다.
  • 즉, T 타입의 모든 속성이 필수가 아니라 선택적으로 처리되어 새로운 타입이 생성됩니다.
interface User {
    name: string;
    age: number;
}

// User의 모든 속성이 선택적으로 처리된 새로운 타입
type PartialUser = Partial<User>;

// 사용 예시:
const partialUser: PartialUser = {}; // 가능
const partialUser2: PartialUser = { name: "Alice" }; // 가능

 

2. Required<T>:

  • Required<T>는 제네릭 타입 T의 모든 속성을 필수로 만드는 유틸리티 타입입니다.
  • 즉, T 타입의 모든 속성이 선택적이었더라도 이를 필수로 처리하는 새로운 타입이 생성됩니다.
interface PartialUser {
    name?: string;
    age?: number;
}

// PartialUser의 모든 속성이 필수로 처리된 새로운 타입
type RequiredUser = Required<PartialUser>;

// 사용 예시:
const requiredUser: RequiredUser = { name: "Bob", age: 30 }; // 가능
const requiredUser2: RequiredUser = { name: "Alice" }; // 오류:

 

3. Pick<T, K>:

  • Pick<T, K>는 제네릭 타입 T에서 속성의 하위 집합을 선택하여 새로운 타입을 생성하는 유틸리티 타입입니다.
  • K에는 T 타입에서 선택하고자 하는 속성의 이름을 문자열 리터럴 타입으로 전달합니다.
interface User {
    name: string;
    age: number;
    email: string;
}

// User에서 name과 age 속성만 선택하여 새로운 타입 생성
type UserInfo = Pick<User, "name" | "age">;

// 사용 예시:
const userInfo: UserInfo = { name: "Alice", age: 30 }; // 가능
const userInfo2: UserInfo = { name: "Bob" }; // 오류: age 속성이 필요함

클래스, 상속, 추상 클래스의 인터페이스

1. 클래스 (Class): 클래스는 객체를 생성하기 위한 템플릿으로, 객체의 상태(속성)와 행위(메서드)를 정의하는 데 사용됩니다. 클래스를 사용하여 객체를 생성하고, 해당 객체의 속성과 메서드에 접근할 수 있습니다.

class Person {
    name: string;
    age: number;

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

    sayHello() {
        console.log(`Hello, my name is ${this.name} and I am ${this.age} years old.`);
    }
}

const person = new Person("John", 30);
person.sayHello(); // 출력: Hello, my name is John and I am 30 years old.

 

2. 상속 (Inheritance): 상속은 클래스 간의 계층 구조를 구성하는 개념으로, 한 클래스(자식 클래스)가 다른 클래스(부모 클래스)의 속성과 메서드를 상속받는 것을 의미합니다. 자식 클래스는 부모 클래스의 기능을 재사용하고 확장하여 자신만의 기능을 추가할 수 있습니다.

class Employee extends Person {
    jobTitle: string;

    constructor(name: string, age: number, jobTitle: string) {
        super(name, age);
        this.jobTitle = jobTitle;
    }

    introduce() {
        console.log(`Hello, my name is ${this.name}, I am ${this.age} years old, and my job title is ${this.jobTitle}.`);
    }
}

const employee = new Employee("Alice", 25, "Software Engineer");
employee.introduce(); // 출력: Hello, my name is Alice, I am 25 years old, and my job title is Software Engineer.

 

3. 추상 클래스 (Abstract Class): 추상 클래스는 직접 객체를 생성할 수 없으며, 다른 클래스에서 상속받아 사용하는 기본 템플릿 역할을 하는 클래스입니다. 추상 클래스는 하나 이상의 추상 메서드를 포함할 수 있으며, 이 메서드는 자식 클래스에서 반드시 구현해야 합니다.

abstract class Shape {
    abstract getArea(): number;
}

class Circle extends Shape {
    radius: number;

    constructor(radius: number) {
        super();
        this.radius = radius;
    }

    getArea() {
        return Math.PI * this.radius * this.radius;
    }
}

const circle = new Circle(5);
console.log(circle.getArea()); // 출력: 78.53981633974483

 

4. 인터페이스 (Interface): 인터페이스는 객체의 형태(shape)를 정의하는 역할을 합니다. 클래스가 특정 인터페이스를 구현(Implements)하면, 해당 인터페이스에서 정의한 모든 속성과 메서드를 구현해야 합니다.

interface Vehicle {
    brand: string;
    wheels: number;
    start(): void;
    stop(): void;
}

class Car implements Vehicle {
    brand: string;
    wheels: number;

    constructor(brand: string) {
        this.brand = brand;
        this.wheels = 4;
    }

    start() {
        console.log(`${this.brand} car is starting...`);
    }

    stop() {
        console.log(`${this.brand} car is stopping...`);
    }
}

const car = new Car("Toyota");
car.start(); // 출력: Toyota car is starting...

SOLID 객체지향 설계 5가지 원칙

  1. SRP (Single Responsibility Principle, 단일 책임 원칙):
    • 클래스는 단 하나의 책임만 가져야 합니다.
    • 하나의 클래스가 너무 많은 책임을 지면 변경 사항이 발생했을 때 다른 책임과의 의존성이 생겨서 코드의 변경이 어려워집니다.
    • 따라서 각 클래스는 한 가지 주요한 책임만 가져야 하며, 해당 책임에만 집중하여 설계해야 합니다.
  2. OCP (Open-Closed Principle, 개방-폐쇄 원칙):
    • 확장에는 열려있고, 변경에는 닫혀 있어야 합니다.
    • 기존의 코드를 변경하지 않고도 기능을 확장할 수 있도록 설계되어야 합니다.
    • 이를 위해 인터페이스, 추상 클래스 등을 활용하여 구체적인 구현에 의존하는 것이 아니라 추상화된 인터페이스에 의존하도록 해야 합니다.
  3. LSP (Liskov Substitution Principle, 리스코프 치환 원칙):
    • 자식 클래스는 언제나 부모 클래스로 대체할 수 있어야 합니다.
    • 즉, 자식 클래스는 부모 클래스가 정의한 규약을 지켜야 하며, 부모 클래스에서 정의한 기능을 모두 수행할 수 있어야 합니다.
    • 이를 통해 다형성(polymorphism)을 지원하고, 코드의 재사용성과 유연성을 높일 수 있습니다.
  4. ISP (Interface Segregation Principle, 인터페이스 분리 원칙):
    • 클라이언트는 자신이 사용하지 않는 인터페이스에 의존해서는 안 됩니다.
    • 하나의 큰 인터페이스보다는 여러 개의 작은 인터페이스로 분리하여 클라이언트가 필요한 기능에만 의존할 수 있도록 해야 합니다.
    • 이를 통해 불필요한 의존성을 제거하고 인터페이스의 더욱 명확한 구조를 유지할 수 있습니다.
  5. DIP (Dependency Inversion Principle, 의존성 역전 원칙):
    • 상위 수준의 모듈은 하위 수준의 모듈에 의존해서는 안 됩니다. 두 모듈 모두 추상화된 인터페이스에 의존해야 합니다.
    • 즉, 상위 수준의 모듈이 하위 수준의 모듈에 직접 의존하는 것이 아니라 추상화된 인터페이스에 의존하도록 설계해야 합니다.
    • 이를 통해 모듈 간의 결합도를 낮추고, 유연하고 확장 가능한 구조를 구현할 수 있습니다.

 

 

+ Recent posts