타입스크립트 기초 : public, private / Interface / Type Alias / Generics

chichi·2023년 3월 18일
0

public, private

: 접근 제한자, 객체 지향 프로그래밍의 *캡슐화를 위해 사용

*캡슐화(encapsulation) : 객체의 상태와 행동을 외부에 감추고 필요한 정보만 외부에 노출시키는 것. 코드의 재사용성을 높이고 유지보수를 용이하게 함

interface Shape {
  getArea(): number;
}
// 멤버 변수를 선언한 다음에 constructor 에서 다시 설정할 필요 없이, 
// (ex: width:number를 지정하고 생성자 부분에서 다시 width:number)
// constructor의 파라미터 쪽에서 public 또는 private를 사용하면 직접 설정하는 작업 생략 가능
// 또한 외부에서 직접적인 변경을 막는 역할도 함 -> 클래스 내부 데이터 보호, 객체의 일관성과 코드의 신뢰성을 유지

class Circle implements Shape {
  constructor(public radius: number) {
    this.radius = radius;
  }
  getArea() {
    return this.radius * this.radius * Math.PI;
  }
}

class Rectangle implements Shape {
  constructor(private width: number, private height: number) {
    this.width = width;
    this.height = height;
  }
  getArea() {
    return this.width * this.height;
  }
}

// shapes: Shape[]는 Shape 인터페이스를 구현한 객체들을 담을 수 있는 배열
const shapes: Shape[] = [new Circle(5), new Rectangle(10, 5)];
// shapes를 반복하는데 shape 하나씩 돌면서 shape의 getArea 함수를 한 번씩 실행한 콘솔 로그를 출력함
shapes.forEach((el) => console.log(el.getArea()));
  • public, private를 사용하는 것에 대해 막연히 이해하고 있었는데,이렇게 생성자 부분에 public, private를 표기하면 위에서 선언할 필요가 없고 캡슐화 된다는 것을 보다 명확히 이해할 수 있었다.
  • const shapes: Shape[] = [new Circle(5), new Rectangle(10, 5)] 로 작성하면, Shape 인터페이스를 구현한 객체들을 담을 수 있는 배열이 된다. 따라서 shapes 배열에는 Shape 인터페이스에서 정의된 getArea() 메서드를 구현한 객체들만 담을 수 있게 된다. 이러한 형식은 다형성(polymorphism)을 지원하며, 코드의 유연성과 확장성을 높여준다는 것을 알게 되었다.

출처 : https://react.vlpt.us/using-typescript/01-practice.html


일반 객체를 interface로 타입 설정하기

interface Person {
  name: string;
  age?: number; // optional. 설정해도 되고 안해도 되는 값
}

interface Developer {
  name: string;
  age?: number;
  skills: string[];
}

const person: Person = {
  name: '홍길동',
  age: 20
}

const expert: Developer = {
  name: '김코딩',
  age: 25,
  skills: ["javascript", "react"]
}

유사한 형태를 띄는 interface 상속 가능

→ 코드의 안정성을 보장, 객체 간의 상속 및 호환성을 체크할 수 있게 된다

interface Person {
  name: string;
  age?: number; // optional. 설정해도 되고 안해도 되는 값
}

interface Developer extends Person { // extends 키워드로 상속
  skills: string[];
}

const person: Person = {
  name: "홍길동",
  age: 20,
};

const expert: Developer = {
  name: "김코딩",
  age: 25,
  skills: ["javascript", "react"],
};

const people: Person[] = [person, expert];
console.log(people);

Type Alias

TypeScript에서 새로운 타입을 정의하기 위한 문법.

기존에 있는 타입들을 더 직관적이고 명확하게 표현할 수 있다.

type Person = {
  name: string;
  age?: number; // optional. 설정해도 되고 안해도 되는 값
};

// &은 Intersection
// 두 개 이상의 타입들을 합쳐줌
type Developer = Person & {
  skills: string[];
};

const person: Person = {
  name: "홍길동",
};

const expert: Developer = {
  name: "김코딩",
  skills: ["javascript", "react"],
};

type Color = "red" | "orange" | "pink";
const color: Color = "red";
const colors: Color[] = ["orange", "pink"];
console.log(color); // red
console.log(colors); // [ 'orange', 'pink' ]

type은 특정 타입에 별칭을 붙이는 용도로 사용.

→ 객체를 위한 타입 설정

→ 배열 또는 그 어떤 타입이던 별칭을 지어줄 수 있다

타입 VS 인터페이스

클래스와 관련된 타입 : 인터페이스

일반 객체와 관련된 타입 : 타입

일관성 있게 사용하는 것이 중요하다.

Generics?

타입스크립트에서 함수, 클래스, interface, type alias 를 사용하게 될 때 여러 종류의 타입에 대하여 호환을 맞춰야 하는 상황에서 사용하는 문법

함수에서 Generics 사용하기

function merge(a: any, b: any): any {
  return { ...a, ...b };
}

const merged = merge({ foo: 1 }, { foo: 2 });
console.log(merged);

위처럼 제네릭을 사용하지 않고, any 타입을 사용하면 타입 유추가 깨진 것과 다름 없다

function merge<A, B>(a: A, b: B): A & B {
  return { ...a, ...b };
}

const merged = merge({ foo: 1 }, { foo: 2 });
console.log(merged);

위처럼 제네릭을 사용해 함수의 유연성, 타입 안정성을 보장할 수 있도록 작성하는 것이 좋다.

function wrap<T>(param: T) {
  return param;
}

const wrapped = wrap("starbucks");
console.log(wrapped);

위와 같은 방법으로도 사용 가능

interface에서 Generics 사용하기

// Items 인터페이스는 list 배열을 제네릭하게 갖고 있음

// items을 선언하고 이것은 Items 타입을 string으로 가짐
// list 배열 안에는 문자열 'a' 'b' 'c'가 있음

interface Items<T> {
  list: T[];
}

const items: Items<string> = {
  list: ["a", "b", "c"],
};

console.log(items);

types에서 Generics 사용하기

type Items<T> = {
  list: T[];
};

const items: Items<string> = {
  list: ["a", "b", "c"],
};

console.log(items);

interface에서 사용한 방법과 유사함

클래스에서 Generics 사용하기

제네릭을 사용하여 Queue 클래스를 구현한 예시

// Queue 클래스 만들기 : 데이터를 등록할 수 있는 자료형. 먼저 등록한 항목을 뽑아올 수 있음
// Queue 클래스는 제네릭으로 선언됨
// list가 제네릭한 배열 형태로 있음
// 길이를 가져오는 함수 get length
// enqueue는 제네릭한 형태의 item을 받고, 리스트에 item을 추가
// dequeue는 list 배열에서 shift 메서드 사용 (배열에서 첫번째 요소 제거하고 제거된 요소를 반환)

class Queue<T> {
  list: T[] = [];
  get length() {
    return this.list.length;
  }
  enqueue(item: T) {
    this.list.push(item);
  }
  dequeue() {
    return this.list.shift();
  }
}

const queue = new Queue<number>();
queue.enqueue(0);
queue.enqueue(1);
queue.enqueue(2);
queue.enqueue(3);
queue.enqueue(4);
console.log(queue);
console.log(queue.dequeue());
console.log(queue.dequeue());
console.log(queue.dequeue());
console.log(queue.dequeue());
console.log(queue.dequeue());
console.log(queue);

// Queue { list: [ 0, 1, 2, 3, 4 ] }
// 0
// 1
// 2
// 3
// 4
// Queue { list: [] }

Queue 는 데이터를 등록 할 수 있는 자료형이며,

먼저 등록(enqueue)한 항목을 먼저 뽑아올 수(dequeue) 있는 성질을 가지고 있다.

출처 : https://react.vlpt.us/using-typescript/01-practice.html

0개의 댓글