class 키워드를 이용하여 키워드를 만들며, class 이름은 보통 대문자로 시작한다.
new를 이용하여 class를 통해 객체를 만들 수 있다.
자바스크립트로 컴파일되면 es5의 경우 function으로 변경된다.
class Department {
id: number;
name: string;
constructor(id: number, name: string) {
this.id = id;
this.name = name;
}
}
const d = new Department(1, 'seung');
strict 모드에서는 프로퍼티를 선언하는 곳 또는 생성자에서 값을 할당해야 한다.
프로퍼티를 선언하는 곳 또는 생성자에서 값을 할당하지 않는 경우에는 !
를 붙여서 위험을 표현한다.
클래스의 프로퍼티가 정의되어 있지만, 값을 대입하지 않으면 undefined 이다.
class Person {
name: string = 'seung';
age!: number; // 그냥 age 라고만 정의하면 에러 발생하므로 ! 붙여서 위험을 표현
}
const p = new Person();
console.log(p.age); // ❗️undefined
자바스크립트와 동일하게 extends
키워드를 이용하여 상속한다.
class
abstract
키워드 붙여서 사용 abstract class Department {
constructor(public id: number, public name: string) {}
abstract descript(this: Department): void;
}
class ITDepartment extends Department {
constructor(id: number) {
super(id, 'IT');
}
descript() {
console.log(`IT Department - ID: ${this.id}`);
}
}
private
키워드를 붙여 사용class ITDepartment extends Department {
private static instance: ITDepartment;
private constructor(id: number) {
super(id, 'IT');
}
static getInstance() {
if (ITDepartment.instance) {
return this.instance;
}
this.instance = new ITDepartment(1);
return this.instance;
}
descript() {
console.log(`IT Department - ID: ${this.id}`);
}
}
const it = ITDepartment.getInstance();
readonly
제어자 가능 / ~~public
, private
등 불가능~~interface Person {
name: string;
age: number;
greet(phrase: string): void;
}
let user1: Person;
user1 = {
name: 'Seung',
age: 28,
greet(phrase: string) {
console.log(`${phrase} ${this.name}`);
},
};
💡 여기서, 궁금한 점은 사용자 정의 타입으로 사용한다면
type Person = { ... }
과 똑같지 않나?
인터페이스는 객체의 구조를 설명하기 위해서만 사용한다.
또한, 인터페이스를 여러 클래스간 공유하며 해당 구조로 만들어져야 한다고 나타낼 수 있다.
interface Greetable {
name: string;
greet(phrase: string): void;
}
class Person implements Greetable {
age:number = 28;
constructor(public name: string) {}
greet(phrase: string) {
console.log(`${phrase} ${this.name}`);
}
}
인터페이스간 상속하여 확장시킬 수 있다.
❗️ 클래스와 다르게 두 개 이상의 인터페이스를 상속받을 수 있다.
interface Named {
readonly name: string;
}
interface Aged {
age: number;
}
interface Greetable extends Named, Aged {
greet(phrase: string): void;
}
type 대신 인터페이스로 사용자 함수 타입을 나타낼 수 있다.
// type AddFn = (a: number, b: number) => number;
interface AddFn {
(a: number, b: number): number;
}
const add: AddFn = function(num1: number, num2: number) {
return num1 + num2;
}
프로퍼티 식별자 뒤에 ?
를 붙여 사용하며, 해당 변수는 선택적으로 구현해도 된다는 표시이다.
interface Named {
readonly name?: string;
}
class Person implements Named {
name?: string;
constructor(n : string) {
if (n) {
this.name = n;
}
}
}
동일한 이름의 인터페이스를 여러개 생성하면 나중에 해당 인터페이스의 이름으로 사용할 때 여러개가 합쳐진 상태로 사용 가능하다.
interface MergingInterface {
a: string;
}
interface MergingInterface {
b: string;
}
let mi: MergingInterface = {
a: 'a',
b: 'b',
};
public
: 모든 곳에서 접근 가능private
: 자신의 클래스 내에서만 접근 가능 / 외부 접근 불가능 / 확장 클래스 접근 불가능_
를 붙여 표현하는 관습 있음protected
: 외부 접근 불가능 / 확장 클래스 접근 가능💡
readonly
: 특정 속성이 초기화 후엔 변경될 수 없음
생성자 매개변수에 접근제어자 표시를 통해 간략하게 변수 초기화 가능
💩 변경 전
class Department {
private readonly id: number;
public name: string;
constructor(id: number, name: string) {
this.id = id;
this.name = name;
}
}
✨ 변경 후
class Department {
constructor(private readonly id: number, public name: string) {}
}