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