TypeScript(타입스크립트) Class

NSH·2022년 6월 2일
0

TypeScript

목록 보기
6/8

1. 클래스(Class)

자바스크립트는 재사용 가능한 컴포넌트를 만들기 위해 함수와 프로토타입 기반의 상속을 사용한다. ES6 부터는 객체 지향 클래스 기반 접근 방식을 사용해서 어플리케이션을 만들 수 있다.

2. 상속(Inheritance)

타입스크립트에는 일반적인 객체 지향 패턴을 사용할 수 있다. 클래스 기반 프로그래밍의 기본 패턴인 상속을 사용해서 클래스를 확장(상속)해서 새로운 클래스를 만들 수 있다.

아래의 코드는 상속의 가장 기본적인 예제이다. Dog는 extends 키워드를 사용해서 Animal의 프로퍼티와 메소드를 상속받는다. 이 때 Dog는 하위 클래스 Animal은 상위 클래스라고 부른다.

// 상위 클래스
class Animal {
	move(distance: number = 0) {
    	console.log('distance : ', distance);
    }
}

// 하위 클래스
class Dog extends Animal {
	bark() {
    	console.log('woof!');
    }
}

const dog = new Dog();
dog.bark(); 	// 'woof!'
dog.move(10); 	// 'distance : 10'

2.1 상위 클래스 생성자 실행

하위 클래스는 상위 클래스의 생성자를 실행하기 위해서 super()를 호출해야 한다. 생성자 내에서 this에 있는 프로퍼티에 접근하기 전에 super()가 먼저 호출되어야 한다.

// 상위 클래스
class Animal {
	name: string;
  	
  	constructor(theName: string) {
    	this.name = theName;
    }
  
  	move(distance: number = 0) {
    	console.log(`${this.name} moved ${distance}m.`);
    } 
}
// 하위 클래스
class Snake extends Animal {
	constructor(name: string) {
      	// 상위 클래스 생성자 실행
    	super(name);
    }
}

const snake = new Snake('snake_name');
snake.name;		// 'snake_name';
snake.move(10); // 'snake_name moved 10m.'

2.2 오버라이드

상위 클래스의 메서드를 하위 클래스에 특화된 메서드로 오버라이드 하는 방법이 존재한다.

// 상위 클래스
class Animal {
	name: string;
  	
  	constructor(theName: string) {
    	this.name = theName;
    }
  
  	move(distance: number = 0) {
    	console.log(`${this.name} moved ${distance}m.`);
    } 
}
// 하위 클래스
class Snake extends Animal {
	constructor(name: string) {
      	// 상위 클래스 생성자 실행
    	super(name);
    }
  	
  	// 오버라이드
  	move(distance: number = 10) {
    	console.log('snake move......');
      	super.move(distance);
    }
}
const snake = new Snake('snake_name');
snake.name;		// 'snake_name';
snake.move(10); // 'snake move......, snake_name moved 10m.'

3. public

위에서 다룬 예제들은 프로그램 내에 선언된 맴버에 자유롭게 접근이 가능하다. 타입스크립트는 기본적으로 각 맴버가 public 속성을 가지며 명시적으로 public으로 표시할 수 있다. Animal 클래스를 다음과 같은 방식으로 작성 가능하다.

class Animal {
	public name: string;
  	public constructor(theName: string) { this.name = theName; }
  	public move(distance: number) { console.log(`${this.name} moved ${distance}m.`); }
}

4. private

타입스크립트는 클래스 외부에서 멤버에 접근하지 못하도록 멤버를 private로 표시하는 방법이 존재한다.

class Animal {
	private name: string;
  	constructor(theName: string) { this.name = theName; }
}

// Property 'name' is private and only accessible within class 'Animal'.
new Animal('cat').name;

타입스크립트의 private 는 javascript 코드로 어떻게 트랜스파일 될까? 코드를 보면 알겠지만 Animal 생성자 함수를 반환하고 Animal 생성자 함수로 만든 인스턴스를 통해서 name에 접근이 가능하다.

타입스크립트 컴파일러가 private 키워드를 보고 클래스 외부에서 사용 시 에러를 발생시켜주는 것일뿐 자바스크립트에서 private를 위해서 어떤 작업도 하고 있지 않다.

// typescript
class Animal {
	private name: string;
  	constructor(theName: string) { this.name = theName; }
}

// transpile javascript
var Animal = /** @class */ (function () {
    function Animal(theName) {
        this.name = theName;
    }
    return Animal;
}());
var snake = new Animal('snake_name');
snake.name; // snake_name;

5. protected

protected 지정자는 protected로 선언된 멤버를 파생된 클래스 내에서 접근할 수 있다는 점만 제외하면 private 지정자와 매우 유사하다.

class Person {
  	protected name: string;
    constructor(name: string) { this.name = name; }
}

class Employee extends Person {
	private  department: string;
  	
  	constructor(name: string, department: string) {
    	super(name);
      	this.department = department;
    }
 
  	public getElevatorPitch() {
      	// name은 protected 지정자로 파생 클래스 내부에서 접근이 가능하다.
      	// name이 private 지정라도 되어있다면 파생 클래스 내부에서도 접근이 불가능하다.
    	return `${this.name} work in ${this.department}`
    }
}

let sangho = new Employee('sangho', 'Sales');
sangho.getElevatorPitch(); // 'sangho work in Sales'
// 파생 클래스 내부에서만 접근이 가능하기 때문에 오류가 발생한다.
// Property 'name' is protected and only accessible within class 'Person' and its subclasses.
sangho.name; 

6. 읽기 전용(readonly)

readonly 키워드를 사용해서 프로퍼티를 읽기 전용으로 만들 수 있다. 읽기 전용 프로퍼티는 선언 또는 생성자에서 초기화 해야한다.

class Person {
	readonly name: string;
	constructor(name: string) { 
    	this.name = name;
    }
}

const sangho = new Person('sangho');
// 읽기 전용 프로퍼티로 수정이 불가능
// Cannot assign to 'name' because it is a read-only property.
sangho.name = 'hosang';

7. 매개변수 프로퍼티(Parameter properties)

매개변수 프로퍼티를 사용하면 선언과 할당을 한 번에 할 수 있다.

class Person {
  	// 선언과 할당이 일어난다.
	constructor(readonly name: string) { }
}

const sangho = new Person('sangho');
// 읽기 전용 프로퍼티로 수정이 불가능
// Cannot assign to 'name' because it is a read-only property.
sangho.name = 'hosang';

8. 접근자(Accessors)

타입스크립트는 객체의 멤버에 접근을 가로채는 방식으로 getters/setters를 지원한다. 이를 통해서 객체의 멤버에 접근하는 방법을 세밀하게 제어가 가능하다.

class Employee {
	fullName: string;
}

let employee = new Employee();
employee.fullName = 'sangho';

if(employee.fullName) {
	console.log(employee.fullName); // 'sangho'
}

백업 데이터베이스 필드의 길이와 호환되는지 확인하기 위해서 newName의 길이를 확인하는 setter를 추가할 수 있다. 만약 길이를 초과하면 오류를 발생시킨다.

const maxLength = 10;

class Employee {
	private _fullName: string;

  	get fullName(): string {
    	return this._fullName;
    }
  
  	set fullName(newName: string) {
    	if(newName && newName.length > maxLength) {
        	throw new Error("fullName has a max length of " + maxLength);
        }

		this._fullName = newName;
    }
}

let employee = new Employee();
// 최대 길이(10)를 초과하지 않으므로 정상적으로 값이 할당된다.
employee.fullName = 'fullName';
// 최대 길이(10)를 초과해서 오류가 발생한다.
employee.fullName = 'fullNamefullName';

9. 전역 프로퍼티(Static Properties)

전역 프로퍼티는 클래스와는 연결되어 있지만, 해당 클래스의 인스턴스와는 연결되어 있지 않다. 전역 메서드는 어플리케이션의 유틸리티 함수를 만드는데 사용되며 static 키워드로 선언한다.

class MathUtil {
  	// 정적 메서드
	static add(num1: number, num2: number) {
    	return num1 + num2;
    }
  	// 정적 메서드
	static sub(num1: number, num2: number) {
    	return num1 - num2;
    }
}

const addNum = MathUtil.add(1, 2); // 3
const subNum = MathUtil.sub(2, 1); // 1

10. 추상 클래스(Abstract Classes)

  • 다른 클래스들이 파생될 수 있는 기초 클래스이다.
  • 인터페이스와 달리 멤버에 대한 구현 세부 정보를 포함할 수 있다.
  • 정의되지 않은 추상 메서드를 포함하고 있으므로 직접 인스턴스를 생성할 수 없다.
abstract class Animal {
  	// 추상 메서드로 구현을 포함하지 않는다.
	abstract: makeSound(): void;
  	move(): void {
    	console.log('moving....')
    }
}

11. 추상 메서드(Abstract Method)

  • abstract 키워드는 추상 메서드를 정의하는데도 사용된다.
  • 추상 메서드는 구현을 포함하지 않으며 파생 클래스에서 구현해야 한다.
abstract class Person {
	constructor(public name: string, public age: number) { }
  
  	printName(): void { 
      console.log('name : ' + this.name); 
    }
  
  	// 추상 클래스로 파생된 클래스에서 구현되어야 한다.
  	abstract printAge(): void;
}

class Employee extends Person {
  	// 파생된 클래스의 생성자는 만드시 super(부모 클래스 생성자)를 호출해야한다.
	constructor(public name: string, public age: number) {
    	super(name, age);
    }
  
    printAge() {
    	console.log('age : ' + this.age);
    }
}

const sangho = new Employee('sangho', 50);
sangho.printName(); // 'sangho';
sangho.printAge(); 	// 50
profile
잘 하고 싶다.

0개의 댓글