한 걸음씩

[TypeScript] Class, Interface 본문

TypeScript

[TypeScript] Class, Interface

winter17 2023. 8. 3. 12:22

 클래스

  • 클래스는 객체를 생성하기 위한 템플릿으로서, 해당 클랙스로부터 생성된 객체를 인스턴스라고 한다
  • 클래스를 사용하면 데이터와 해당 데이터에 대한 메서드를 하나로 묶어서 사용자 정이 타입을 생성할 수 있다
public(생략가능)
선언한 클래스 내, 상속받은 클래스 내, 인스턴스 모두 접근 가능
protected
선언한 클래스 내, 상속받은 클래스 내에서 접근 가능
private(#변수명)
선언한 클래스 내에서만 접근 가능

 

// TypeScript 코드
class Player{
    constructor(
        private firstName: string,
        private lastName: string,
        public nickName: string
    ){}
}
// nico라는 객체를 Player 클래스를 이용하여 생성
// nico는 Player 클래스의 인스턴스
// 인스턴스: 클래스를 기반으로 생성된 객체를 의미한다. 클래스를 통해 생성된 개별 객체를 인스턴스라고 한다
const nico = new Player('nico', 'las', '니꼬')

nico.nickName // public은 클래스 내부, 외부에서 접근할 수 있다
// 반면, private은 해당 클래스 내에서만 접근할 수 있다

// JavaScript 코드
"use strict";
class Player {
    constructor(firstName, lastName, nickName) {
        this.firstName = firstName;
        this.lastName = lastName;
        this.nickName = nickName;
    }
}
const nico = new Player('nico', 'las', '니꼬');
nico.nickName;

 

// 접근제한자 - public, private, protected
class Car{
    readonly name: string = 'car'
    color: string
    static wheels = 4
    constructor(color: string, name: string){
        this.color = color
        this.name = name
    }
    start(){
        console.log('start')
        console.log(this.name)
        console.log(Car.wheels)
    }
}

class Bmw extends Car {
    constructor(color: string, name: string){
        super(color, name)
    }
    showName(){
        console.log(super.name)
    }
}
const z4 = new Bmw('black', '이름')
console.log(z4.name) // '이름'
console.log(Car.wheels) // 4

 

▷ abstract class

  • 인스턴스를 직접 생성할 수 없는 클래스, 단순히 상속을 위해 사용되며, 자체적으로 객체를 생성할 수 없다.(new사용X)
  • 추상 클래스를 상속받은 자식 클래스는 추상 메서드를 반드시 구현해야 하며, 구현이 없을 경우 컴파일 오류가 발생한다.
  • 추상메서드를 선언할 때에는 메서드 이름 뒤에 'abstract' 키워드를 붙이고, 중괄호 대신 세미콜론으로 마무리한다
  • 일반적으로 공통된 기능을 가진 클래스를 정의하고, 이를 상속받아 구체적인 동작으로 하는 클래스를 만들 때 사용된다. 
  • 코드의 재사용성과 유지보수성을 높일 수 있다.
  • 추상 클래스는 다른 클래스가 상속받을 수 있는 클래스인데, 이 클래스는 직접 새로운 인스턴스를 만들 수 없다
  • 자바스크립트로 확인해보면 그냥 클래스로 보여진다.
// 추상 클래스
abstract class Car{
    color: string // color 프로퍼티
    constructor(color: string){ // constructor 메서드 ; 객체 생성시 색상을 인자로 받아서 color프로퍼티 초기화
        this.color = color
    }
    start(){ // start 메서드 ; 'start' 문자열을 출력하는 기본 구현
        console.log('start')
    }
    // doSomething()메서드가 추상 메서드로 선언되어 있으므로 Car 클래스를 상속받은 하위 클래스에서 반드시 구현해야 한다
    abstract doSomething(): void // 추상 메서드이므로 실제 동작 구현이 없음
}

// 추상 클래스는 반드시 상속받아서 사용해야 한다
// Bmw는 Car 클래스를 상속받은 하위 클래스, doSomething 메서드를 구현
class Bmw extends Car {
    constructor(color: string){
        super(color)
    }
    doSomething(){
        alert(3) // 호출 -> Car클래스의 추상성 해소, 실제로 동작하는 클래스를 만듦
    }
}
const z4 = new Bmw('black') // Bmw 클래스를 인스턴스화하여 z4변수에 할당
// z4변수는 Bmw 클래스의 인스턴스가 된다
// z4변수는 Car 추상 클래스로부터 상속된 color 프로퍼티와 start메서드를 가지고 있고
// Bmw 클래스에서 구현한 doSomething 메서드도 가지고 있다

 

⊙ 추상 메소드

  • 추상 클래스 안에 들어간 추상 메소드 : 클래스 안에서 구현하지 않으면 됨
  • 추상 메소드: 추상 클래스를 상속받는 모든 것들이 구현을 해야하는 메소드를 의미
  • 메소드: 클래스 안에 존재하는 함수

◆ 인터페이스

let user:object
user={
    name:'xx',
    age: 30
}
// user가 object타입이지만, name, age의 타입이 명시되지 않았기 때문에 오류 발생
console.log(user.name)

 

▷ interface

  • 클래스가 어떤 프로퍼티와 메서드를 가져야 하는지를 정의하는 일종의 '계약서'
  • 인터페이스는 클래스가 반드시 구현해야 하는 멤버(프로퍼티, 메서드)들의 목록을 제공한다
  • 인터페이스 자체로는 구현이 이루어지지 않으며, 단지 클래스가 따라야 하는 규칙들을 명시하는 역할을 한다
  • 자바스크립트로 컴파일되지 않는다!!
  • type, interface는 오브젝트의 모양과 타입을 알려주는 같은 목표를 가졌지만, type은 상속할 때 또 다른 타입을 만들어야한다. interface는 상속할 때 객체 지향 프로그래밍과 같은데 extends를 사용한다. interface는 이후에 타입을 추가할 때 다시 선언하여 사용할 수 있다. 반면 type은 같은 변수를 가진채 타입을 추가하면 duplicate되어 에러가 발생한다.
  • type은 객체 뿐만 아니라 다양한 데이터 타입을 정의하는 데 사용된다
  • interface는 객체의 구조와 형태를 정의하는 데 주로 사용된다.
type Score = 'A' | 'B' | 'C' | 'D'
interface User{
    name:string,
    age:number,
    // '?' : 선택
    gender?:string
    // readonly 속성은 읽기만 가능! 수정X
    readonly birthYear : number
    // number를 key로, string을 value로
    // Score에 없는 것들을 사용 불가
    [grade:number] : Score
}
let user:User={
    name:'xx',
    age:10,
    birthYear : 2000,
    1 : 'A',
    2 : 'B'
}
// 값을 변경할 수 있음
user.age = 20
// 값을 추가할 수 있음
user.gender = 'male'

console.log(user.name) // 'xx'

 

// Add함수의 타입은 number
interface Add{
    (num1:number, num2:number):number
}
const add:Add = function(x, y){
    return x + y
}
add(10, 20) // 30

 

// IsAdult함수의 타입은 boolean
interface IsAdult {
    (age:number):boolean
}
const a:IsAdult = (age) =>{
    return age > 19
}
a(40) // true

 

 

▷ implement

  • 클래스가 특정 인터페이스를 구현한다는 것을 나타내는 역할을 한다
  • 클래스가 인터페이스의 모든 멤버를 반드시 구현해야 함을 의미하는 것이다

▷ class

  • 객체를 생성하기 위한 설계도 또는 템플릿으로, 객체 지향 프로그래밍에서 데이터와 해당 데이터에 관련된 동작(메서드)을 하나로 묶는 데 사용된다.
  • 클래스는 객체의 속성(프로퍼티)과 동작(메서드)를 정의하는 멤버들로 구성된다
  • 객체는 클래스를 기반으로 생성되며, 생성된 객체를 클래스의 인스턴스라고 한다.

▷ constructor

  • 생성자
  • 클래스의 인스턴스를 초기화하는 특별한 메서드
  • 클래스로부터 객체를 생성할 때, 생성자가 호출되어 객체의 초기 상태를 설정한다.
  • 생성자는 클래스의 이름과 동일한 이름을 가지며, constructor 키워드를 사용하여 정의한다.
  • 생성자는 객체가 생성될 때 자동으로 호출되므로, 객체를 생성할 때 필요한 초기화 작업을 수행하는 데 사용된다.

▷ instance

  • 클래스의 구조를 바탕으로 실제로 메모리에 할당된 객체
  • 클래스는 템플릿이고, 인스턴스는 이 템플릿을 기반으로 만들어진 객체
  • 인스턴스는 클래스의 구조대로 생성되기 때문에 클래스에서 정의한 변수(프로퍼티)와 메서드를 모두 가질 수 있다
  • 클래스의 구조에 따라 동작하며, 각각의 인스턴스는 서로 독립적으로 동작한다. 
  • Bmw클래스는 color, wheels 프로퍼티와 start() 메서드를 가지고 있다. Bmw클래스의 인스턴스를 생성하면 해당 인스턴스는 color, wheels 프로퍼티를 가지고 있고, start()메서드를 호출할 수 있다.

 

interface Car{
	// 프로퍼티
    color:string
    wheels:number
    // 메서드
    start():void
}

// Car 인터페이스를 implement키워드를 사용하여 Bmw 클래스 구현
// -> color, wheels, start 메서드를 반드시 구현해야 함
class Bmw implements Car{
    color;
    wheels = 4
    
    // Bmw 클래스의 생성자는 c라는 매개변수를 받아서 color 프로퍼티에 값을 할당하는 역할을 수행하고 있음
    constructor(c:string){
    	// 생성자 내에서 객체의 프로퍼티에 값을 할당
        // this.color는 color 프로퍼티를 의미
        this.color = c 
    }
    start(){
        console.log('go...')
    }
}

// 생성자는 new 키워드와 함께 클래스를 인스턴스화할 때 자동으로 호출
// b변수는 Bmw 클래스의 인스턴스이며, 이 인스턴스는 color, wheels, start() 메서드를 가지고 있다
const b = new Bmw('green')

console.log(b)
// Bmw: {
//   "wheels": 4,
//   "color": "green"
// }

wheels 프로퍼티는 클래스 내에서 직접 초기값을 지정했는데 이런 방법은 정적으로 값을 할당하는 방법이기 때문에 클래스가 인스턴스화될 때마다 항상 동일한 초기값을 가지게 된다. 이 경우에 객체가 생성될 때마다 다른 초기값을 제공할 수 없기 때문에 유연성이 떨어진다.

 

반면에, color 프로퍼티는 생성자 내에서 초기값을 지정했는데, 외부에서 객체를 생성할 때 매개변수를 통해 다양한 초기값을 전달할 수 있다. 이렇게 하면 같은 클래스의 인스턴스라도 각각 다른 초기값을 가질 수 있으며, 이를 통해 객체의 다양한 상태를 표현하고 다양한 상황에 유연하게 대처할 수 있다.

 

class Person {
  name: string;
  age: number;

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

// 외부에서 Person 클래스의 생성자를 호출하여 객체 생성
const person1 = new Person("Alice", 30);
const person2 = new Person("Bob", 25);

console.log(person1); // Person { name: 'Alice', age: 30 }
console.log(person2); // Person { name: 'Bob', age: 25 }

 

▷ extends

  • 클래스 간 상속을 구현하는 키워드
  • 이미 존재하는 클래스를 기반으로 새로운 클래스를 만들 때 사용
  • 상속을 통해 기존 클래스의 프로퍼티와 메서드를 재사용하고, 새로운 기능을 추가하거나 기존 기능을 변경할 수 있다
  • extends 키워드를 사용하여 클래스 상속을 구현할 때, 하위 클래스는 상위 클래스의 모든 멤버를 상속받게 된다. 
  • 하위 클래스는 상위 클래스의 멤버를 사용하거나 오버라이딩(재정의)하여 자신만의 동작을 구현할 수 있다
// 상위 클래스 (부모 클래스)
class Animal {
  constructor(public name: string) {}

  // 메서드
  makeSound() {
    console.log("Animal makes a sound");
  }
}

// 하위 클래스 (자식 클래스)
class Dog extends Animal {
  constructor(name: string) {
    super(name); // 상위 클래스의 생성자 호출
  }

  // 오버라이딩: 상위 클래스의 메서드를 재정의
  makeSound() {
    console.log("Dog barks");
  }

  // 자식 클래스의 메서드
  fetch() {
    console.log("Dog fetches a ball");
  }
}

// 하위 클래스의 인스턴스 생성
const myDog = new Dog("Buddy");

console.log(myDog.name); // "Buddy"
myDog.makeSound();       // "Dog barks"
myDog.fetch();           // "Dog fetches a ball"

 

interface Car{
    color: string
    wheels:number
    start():void
}

interface Toy{
    name:string
}
interface ToyCar extends Car, Toy{
    price:number
}

 


 

◆ 참고 공식 문서

 

https://www.typescriptlang.org/docs/handbook/interfaces.html

 

 

Handbook - Interfaces

How to write an interface with TypeScript

www.typescriptlang.org

https://www.typescriptlang.org/docs/handbook/classes.html

 

Handbook - Classes

How classes work in TypeScript

www.typescriptlang.org

 


2023.08.05 - [TypeScript] - [TypeScript] class, interface 연습문제