-
[TS] 클래스codeStates front-end/Typescript 2023. 3. 20. 21:26반응형
목차
📌 클래스
📍클래스
타입스크립트는 자바스크립트와 동일하게 클래스를 선언하고 사용할 수 있다.
클래스란? 여러 객체들을 생성하기 위한 탬플릿 (EX) 클래스 : 붕어빵 기계, 객체 : 붕어빵)
클래스의 핵심 기능은 상속!!!! 👉🏼👉🏼 효율적이고 유지보수가 편함
빈 클래스를 생성해서 새로운 프로퍼티를 선언
class Site { no: number = 0; }
🔗 클래스 메서드
클래스는 기본적으로 속성과 메서드를 갖는다.
클래스에서 매게변수 타입에 타입이나 기본값을 지정하지 않으면 any
메서드를 호출하려면 허용 가능한 수의 인수가 필요하고, 재귀함수가 아니라면 대부분 반환타입 유추 가능
빈 프로퍼티 아래에 메소드를 추가
class Site { no: number; constructor(no: number) { this.no = no; } getNo() { return this.no; } }
🔗 클래스 속성
아래 코드를 보면 name은 속성이며, draw()는 메서드를 가리킨다.
class Shape { name: string; constructor(name: string) { this.name = name; // ok! } // 존재하지 않는 멤버의 접근하려고 시도하면 타입 오류 this.nonName = name; //Error draw(x: number, y: number) { console.log("Draw " + this.name + " at " + x + "," + y); } }
TS에서는 클래스의 속성을 읽거나 쓰려면 클래스에 명시적으로 선언
클래스 속성 이름 뒤에 선택적으로 타입 에너테이션이 붙는다.
🔗 함수 속성
JS에서의 클래스 안에 함수 선언1
// 멤버 이름 뒤에 괄호를 붙이는 메서드 접근 방식 class WithMethod{ myMethod(){} } new WithMethod().myMethod === new WithMethod().myMethod;// true
JS에서의 클래스 안에 함수 선언2
// 값이 함수인 속성을 선언하는 방식 class WithPtoperty{ myProperty : () => {} } new WithMethod().myProperty === new WithMethod().myProperty; // false
함수 속성은 클래스 멤버로 할당된 값 👉🏼👉🏼 그 값은 함수
(input : boolean) => string 인 속성을 갖고 있어 number속성은 바로 에러를 알려준다.
🔗 초기화 검사
타입스크립트는 엄격한 컴파일러 설정이 활성화되어 있는 상태
undefined 타입으로 선언된 각 속성이 생성자에서 할당되었는지 확인
초기화 검사는 클래스 속성에 값을 할당하지 않는 실수를 예방할 수 있어 유용하다.
class WithValue{ immediate = 0; // ok later : number; // ok(construtor에서 할당) mayBeUndefined : number | undefined; // Ok(undefined가 되는 것이 허용됨) unused : number; // Error constructor(){ this.later = 1; } }
🔗 선택적 속성
클래스는 설정된 인터페이스에 정의된 속성 또는 메서드를 반드시 사용하지 않고, 필요에 따라 선택적으로 사용하고 싶을 수도 있다.
이 경우 옵션(Optional) 속성 설정을 통해 사용자가 선택적으로 사용하게 설정
더보기속성 이름 뒤에 ?를 붙이면 옵션 속성
interface에서 선택적 속성을 이용해서 선언 후 클래스를 선언 해 상속시키는 예제
// 공식사이트 예제 interface ButtonInterface { // 속성 이름 뒤에 ? 기호가 붙으면 옵션 속성이 됩니다. onInit?():void; onClick():void; } class ButtonComponent implements ButtonInterface { // onInit 메서드가 설정되지 않아도 오류를 발생하지 않습니다. onClick() { console.log('버튼 클릭') } }
🔗 읽기 전용 속성(readonly)
말 그대로 읽기 전용을 나타내며 사용할 경우 값 변경 불가
class Site { // readonly 사용 readonly no: number; url: string; constructor(no: number, url: string) { this.no = no; this.url = url; } } const Webisfree = new Site(1, 'webisfree.com'); Webisfree.no = 2; // 에러 발생. Readonly이므로 값 변경이 불가함
🔗 타입으로서의 클래스
타입 시스템은 클래스 자체와 타입 에너테이션에서 사용할 수 있는 타입을 모두 생성하는 부분이 특징이다.
타입 에너테이션을 통해 할당할 수 있는 값만을 타입 스크립트에서 알려준다.
타입스크립트는 클래스의 동일한 멤버를 모두 포함하는 객체 타입 클래스만 할당 가능하다
class Teacher { sayHello(){ console.log("Hello"); } } let teacher : Teacher; teacher = new Teacher(); //ok teacher = "Wahoo!"; // error string 형식은 할당할 수 없습니다.
🔗 클래스와 인터페이스
🙋🏻♂️ 인터페이스란? 클래스나 객체에서 사용할 프로퍼티와 메소드를 클래스 외부에 따로 분리하여 선언할 수 있는 방법
타입스크립트는 클래스 이름 뒤에 implements를 사용하여 클래스나 객체에 사용
아까 선택적 속성의 예제와 같이 볼 수 있다.
// 공식사이트 예제 interface ButtonInterface { // 속성 이름 뒤에 ? 기호가 붙으면 옵션 속성이 됩니다. onInit?():void; onClick():void; } class ButtonComponent implements ButtonInterface { // onInit 메서드가 설정되지 않아도 오류를 발생하지 않습니다. onClick() { console.log('버튼 클릭') } } class ButtonComponent implements ButtonInterface { // 아무 메서드도 정의 되어 있지 않다면 에러 발생 }
interface는 사용할 프로퍼티와 타입을 분리하여 사용할 수 있는 방법입니다. 이처럼 interface를 사용할 경우 동일한 데이터를 여러 번 사용할 때 반복해서 프로터티나 타입 등을 선언하지 않아도 된다는 장점이 있다.
// 인터페이스 만들기 interface ISite { no: number; } // 객체에 인터페이스 사용하기 const mySite: ISite = { no: 1 }; // 함수에 인터페이스 사용하기 const getSiteNo = (site: ISite) => { return site.no; };
타입 에너테이션을 제공하지 않으면 any로 간주
다중 인터페이스로도 구현 가능하다(개수 제한 없이 인터페이스 사용 가능)
class Site implements ISite, IFavorite { }
🔗 클래스 확장
클래스는 확장이 가능
확장하는 개념에서 타입스크립트는 타입 검사를 추가한다.
풀스택, 백엔드, 프론트엔드 개념으로 알아보기
export class FrontEnd { public frontEndSkills = ["html", "css", "js"] public react = () => { console.log('I write code with React') } } // FrontEnd.ts // 확장해주면 FrontEnd.ts의 멤버 변수와 메소드에 접근 가능 export class FullStack extends FrontEnd{ public name: string public age: number constructor(name: string, age: number) { super() this.name = name this.age = age } } // FullStack.ts
🤷🏻 백엔드를 추가하고 싶다면?
export interface BackEndType { backendSkills: Array<string> django: () => void } export class BackEnd { public backendSkills = ["database", "aws", "restapi"] public django() { console.log('I build things with django') } } // BackEnd.ts export class FullStack extends FrontEnd, BackEnd{ // Error public name: string public age: number constructor(name: string, age: number) { super() this.name = name this.age = age } } //Error FullStack.ts
mixin 함수를 추가
프론트엔드클래스를 상속받은 풀스택 클래스 베이스 클래스로 만들어 백엔드 클래스와 확장해주면 된다.
const FullStackExtension = <T extends Constructor>(baseClass: T) => { return class FrontEnd extends baseClass { public frontEndSkills = ["html", "css", "js"] as const public react = () => { console.log('I write code with React') } } } // FullStack.ts export class FullStack extends FullStackExtension(BackEnd) { public name: string public age: number constructor(name: string, age: number) { super() this.name = name this.age = age } } // FullStack.ts
🔗 재정의된 생성자, 메서드, 속성
생성자
JS에서 상속받은 하위 클래스에서는 자체 생성자가 없고 기본 클래스의 생성자를 사용
super라는 키워드를 통해 생성자를 호출한다.
TS에서는 기본클래스의 생성자를 호출 할 때 올바른 매게변수를 사용했는지 확인
예를 들어, class B,C가 A에 상속받는 때 이때 C에서 super라는 키워드 없이 생성자를 생성하면 오류
타입 검사기에서 super() 호풀 전에 A에 있는 메서드의 타입을 참조하기 때문이다.
메서드
하위 클래스의 메서드가 기본 클래스의 메서드에 할당될 수 있는 한 하위 클래스는 기본 클래스와 동일한
이름으로 새 메서드를 다시 선언할 수 있다.
기본 클래스의 모든 메서드 👉🏼👉🏼 하위 클래스에서 사용 가능 새 메서드 타입도 기본 메서드 대신 사용할 수 있어야 한다!
속성
하위 클래스는 새 타입을 기본 클래스의 타입에 할당할 수 있는 한 동일한 이름으로 기본 클래스의 속성을 명시적으로 다시 선언
재정의된 메서드와 마찬가지로 하위 클래스는 기본 클래스의 구조적으로 일치해야 한다.
예를 들어, 기본 클래스의 grade가 number | undefined라면 하위 클래스 또한 number타입으로 선언해야 한다.
🔗 추상 클래스
추상 클래스를 정의할 때는 class 앞에 abstract라고 표기
때로는 일부 메서드의 구현을 선언하지 않고, 대신 하위 클래스가 해당 메서드를 제공할 것을 예상하고
기본 클래스를 만드는 방법이 유용할 수 있다.
// 추상 클래스 abstract class Project { public project_name:string|null = null; private budget:number = 2000000000; // 예산 // 추상 메서드 정의 public abstract changeProjectName(name:string): void; // 실제 메서드 정의 public calcBudget(): number { return this.budget * 2; } } // [오류] // [ts] 추상 클래스의 인스턴스를 만들 수 없습니다. // constructor Project(): Project let new_project = new Project();
🔗 멤버 접근성
접근 제한자 public, private, protected를 지원
#을 추가해 private 클래스 멤버임을 나타낸다.
접근 범위 public protected private 클래스 내부 O O O 자식 클래스 내부 O O X 클래스 인스턴스 O X X class Animal { constructor(public name: string, protected age: number, private breed: string) { this.name = name; this.age = age; this.breed = breed; } protected talk() { console.log(`this animal's name is ${this.name}`); } } const animal = new Animal("Ruby", 2, 'tlrhfmwkqmwhd'); // error : 'talk' 속성은 보호된 속성이며 'Animal' 클래스 및 해당 하위 클래스 내에서만 액세스할 수 있습니다. animal.talk(); class Dog extends Animal{ constructor(name: string, age: number, breed: string) { super(name, age, breed); this.talk(); console.log(this.age); // error : 'breed' 속성은 private이며 'Animal' 클래스 내에서만 액세스할 수 있습니다. console.log(this.breed); } } // this.talk(): this animal's name is Ruby // this.age: 5 const dog = new Dog("Ruby", 5, 'tlrhfmwkqmwhd');
🔗 정적 필드 제한자
static 키워드를 사용해 인스턴스를 생성할 필요 없이, 클래스 자체에서 멤버를 선언
readonly의 접근성 키워드를 함께 사용할 수 있도록 지원
class Mathmatics { // 스태틱 속성 static PI:number = Math.PI; // 스태틱 메서드 // circumference = 둘레(원주) static calcCircumference(radius:number) :number { return this.PI * radius * 2; } static calcCircleWidth(radius:number): number { return this.PI * Math.pow(radius, 2); } } // radius = 반지름 let radius = 4; console.log('PI(원주율) = ', Mathmatics.PI); console.log(`반지름이 ${radius}인 원의 넓이: πr² = `, Mathmatics.calcCircleWidth(radius)); console.log(`반지름이 ${radius}인 원의 둘레: 2πr = `, Mathmatics.calcCircumference(radius));
반응형'codeStates front-end > Typescript' 카테고리의 다른 글
[TS] 제네릭 (0) 2023.03.23 [TS] 타입 제한자 (0) 2023.03.21 [TS] 인터페이스 (0) 2023.03.12 [TS] 배열과 튜플 (0) 2023.03.12 [TS] 함수 (0) 2023.03.12