class Greeter {
constructor(name: string) {
/* name만 쓸경우 any로 유추*/
console.log(`${name}, hello~~`);
}
}
new Greeter("Gim");
/* new Greeter() // Error : 인수 개수*/
class Trip {
destination: string; /* 명시적으로 속성 선언 */
constructor(destination: string) {
this.destination = destination;
console.log(`our trip : ${destination}`);
/* this.year = year; /* Error : 명시적으로 속성 선언 안함*/
}
}
readonly a : string = "abc" /* string 타입*/
readonly b = "abc" /* 리터럴 타입 (abc)*/
class Person {
name: string;
get3: () => void; /* 함수 속성으로 정의 */
constructor(name: string) {
this.name = name;
this.get3 = () => {
console.log(`my name is ${this.name}. from get3()`);
};
}
/* 메서드로 정의 (메서드 체인으로 연결되는 프로토 타입에 정의된 메서드) */
get1() {
console.log(`my name is ${this.name}. from get1()`);
}
/* 메서드로 정의 (각 인스턴스 객체마다 새롭게 할당되는 메서드) */
get2 = () => {
console.log(`my name is ${this.name}. from get2()`);
};
}
! : 속성이 처음 시작되기 전에 undefined값이 할당된다. 의도적으로 클래스 속성에 값을 할당안하고 싶을 때 표기하면 검사를 비활성화시킨다.
class withTS {
a = 0;
b: number;
c: number | undefined;
d: number; /* Error : 초기화검사시 생성자에서 값할당 안됨 */
constructor() {
this.b = 1;
}
}
class withTS {
a = 0;
b: number;
c: number | undefined;
d!: number; /*Error : 초기화검사시 생성자에서 undefined 할당*/
constructor() {
this.b = 1;
}
}
const aaa = new withTS();
console.log(aaa.a); //0
console.log(aaa.b); //1
console.log(aaa.c); //undefined
console.log(aaa.d); //undefined
클래스 생성과 클래스 타입 표기 두가지 역할을 한다. class Teacher {
sayhello() {
return ["hi", "hello"];
}
}
function withT(teacher: Teacher) {
console.log(teacher.sayhello());
}
let teacher: Teacher = new Teacher(); /* 클래스 값 할당*/
withT(new Teacher()); /* ["hi", "hello"]*/
withT({ sayhello: () => ["hah"] }); /* 동일한 멤버를 모두 포함하는 객체 타입 할당 ["hah"]*/
/* withT({ sayhello: () => 123 }); // Error : 객체의 반환 타입이 다름*/
withT(new Teacher()): Teacher 타입의 teacher 인스턴스가 withT의 인자로 들어가 함수 호출된다.withT( { sayhello : () => ['hah'] }): Teacher 타입과 동일한 객체인 { sayhello : () => ['hah'] }가 클래스 인스턴스처럼 할당가능하다.
implements를 표기하여 클래스를 구현한다. Why? any 타입은 컴파일러가 타입 검사를 수행하지 않는 타입으로 해당 값에 대한 타입 검사를 수행하지 않기 때문이다.(위험하므로 비권장)interface Learner {
name: string | number;
study(hours: number): void;
}
/* 인터페이스의 모든 속성이 정의되어 클래스에 있어야 한다.(선택적 속성 제외) */
class Student implements Learner {
name: string; /* string | number 내에서 구현가능하다. (any도 가능) */
age : number; /* 인터페이스에 없는 속성 추가 가능하다. */
constructor(name: string, age: number) {
this.name = name;
this.age = age
}
study(hours: number) {
for (let i = 0; i < hours; i += 1) {
console.log("...study");
}
}
}
/* 다중 상속예시 */
interface Daughter{
favorite : string
}
interface Learner {
name: string | number;
study(hours: number): void;
}
/* ,를 통해 다중상속 가능하다. */
class Student implements Learner, Daughter {
name: string; /* string | number 내에서 구현가능하다. (any도 가능) */
favorite : string; /* string 내에서 구현가능하다. (any도 가능) */
age : number; /* 인터페이스에 없는 속성 추가 가능하다. */
constructor(name: string, age: number, favorite: string) {
this.name = name;
this.age = age;
this.favorite = favorite;
}
study(hours: number) {
for (let i = 0; i < hours; i += 1) {
console.log("...study");
}
}
}
/* 같은 속성의 다른 타입을 가진 인터페이스 사용 불가*/
interface Daughter{
// name : null /* 같은 속성의 다른 타입을 가진 인터페이스는 같이 쓸 수 없다. */
name : string /* 가능 */
}
interface Learner {
name: string | number;
study(hours: number): void;
}
/* ,를 통해 다중상속 가능하다. */
class Student implements Learner, Daughter {
name: string; /* string | number 내에서 구현가능하다. (any도 가능) */
age : number; /* 인터페이스에 없는 속성 추가 가능하다. */
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
study(hours: number) {
for (let i = 0; i < hours; i += 1) {
console.log("...study");
}
}
}
extendsextends로 확장한다.class Teacher {
subject: string;
constructor(subject: string) {
this.subject = subject;
}
}
class StudentTeacher extends Teacher {
url: string;
constructor(subject: string, url: string) {
super(subject);
this.url = url;
}
}
let student1: Teacher;
let student2: Teacher;
student1 = new Teacher("coding");
student2 = new StudentTeacher("coding", "https://");
let student3: StudentTeacher;
let student4: StudentTeacher;
/* student3 = new Teacher("coding"); Error : Property 'url' is missing in type 'Teacher' but required in type 'StudentTeacher'. */
student4 = new StudentTeacher("coding", "https://");
/* 선택속성으로 만들어 에러 방지. 좋은 코드처럼 보이지는 않지만 가능은 하다. */
class StudentTeacher extends Teacher {
url?: string;
constructor(subject: string, url?: string) {
super(subject);
this.url = url;
}
}
let student3: StudentTeacher;
let student4: StudentTeacher;
student3 = new Teacher("coding");
student4 = new StudentTeacher("coding", "https://");
- 하위클래스를 타입으로 가지는 변수가 상위클래스를 생성하여 값 할당하면 포함되어 있지 않은 속성이 존재할 수 있기 때문에 에러가 발생할수도 있다.(선택 속성화하면 에러를 막을 수는 있다.)
생성자 : 자동으로 부모의 생성자를 상속받으므로 추가 속성이 필요하지 않을 경우 생성자를 정의할 필요없다. 그러나, 추가 속성이 필요하면 키워드 super 로 부모의 생성자를 호출하여 받는다.(단, this와 super 를 호출하기 전에 super()를 제일 위에서 선언해야 한다.) 그 후, 추가 속성을 표기한다.(생성자 내에서 값 할당시 멤버의 클래스내 존재여부를 확인하지 않으므로 생성자 밖에 명시적으로 속성 표기도 해줘야 한다.) 속성 : 부모클래스의 메서드를 재정의하고 싶을 때는 자식클래스는 재정의할 속성을 부모클래스의 속성타입보다 더 구체적으로 정의해야 한다.메서드 : 부모클래스의 메서드를 재정의하고 싶을 때는첫번째 매개변수와 반환타입만 동일하면 재정의할 수 있다.class GrandCounter {
count(grades: string[], letter: string) {
return grades.length;
}
}
/* 메서드에서는 첫번째 매개변수와 반환타입만 동일하면 허용한다. */
class Counter1 extends GrandCounter {
count(grades: string[]) {
return grades.length;
}
}
/*첫번째 매개변수는 동일하나 반환타입이 다르므로 에러발생한다. */
class Counter2 extends GrandCounter {
count(grades: string[]) {
return true; //Error
}
} 접근제한자를 이용하여 접근성을 통제한다./* readonly는 접근 제한자 뒤에 표시한다. */
class One {
private readonly name: string;
constructor() {
this.name = "kim";
}
}
const one = new One();정적 필드 : 클래스의 인스턴스가 아닌 클래스 자체에 속하는 필드.
정적 필드 제한자를 사용하여 정적 필드를 사용하면 클래스 외부에서 이 필드에 대한 접근을 제한할 수 있다.
정적 필드 제한자 : readonly, static
/* 'answer'는 public이기에 외부에서 읽을 수 있고 static이기 때문에 클래스에 접근이 가능하다. 'prompt'는 protected이기에 외부에서 접근이 불가하고 static이기 때문에 클래스에 접근이 가능하다. 그러나, 이 코드에서는 클래스 내부/하위클래스에서 접근하는 과정이 없으므로 접근이 불가하다. */
class Question {
public static readonly answer = "bash"; /* 정적필드 제한자 */
protected static readonly prompt = "what"; /* 정적필드 제한자 */
guess(getAnswer: (prompt: string) => string) {
const answer = getAnswer(Question.prompt);
if (answer === Question.prompt) {
console.log("You got it");
} else {
console.log("Try");
}
}
}
const question = new Question();
console.log(Question.answer) /* bash */
// console.log(Question.prompt) /* Error : 접근 불가 */
// question.answer /* Error : 접근 불가 */
// question.prompt /* Error : 접근 불가 */
클래스명와 메서드명 앞에 키워드 abstract 추가한다.extends를 이용하여 추상클래스를 상속받는다.인스턴스화가 불가능하다./* 메서드 getStudent를 구현하지 않은 추상클래스 School */
abstract class School {
readonly name: string;
constructor(name: string) {
this.name = name;
}
abstract getStudent(): string[];
}
/* 메서드 getStudent가 구현되지 않았으므로 에러 발생 */
class PreSchool1 extends School {}
/* 메서드 getStudent가 구현*/
class PreSchool2 extends School {
getStudent(): string[] {
return ["pre"];
}
}