본문 바로가기
TIL

타입스크립트 class / implements

by 은지:) 2023. 7. 9.
728x90
반응형

 

 

1) 오버라이딩

overrriding

부모 클래스에 정의된 메서드를 자식 클래스에서 새로 구현하는 것

overridden class 오버라이든 : 부모 클래스

overridden method 오버라이든 메서드 : 자식 클래스

class Bird {
	오버 라이든 클래스(부모 클래스)

// 오버라이든 메서드
	flight(km : number | string ){
	...}

}

class Eagle extends Bird {
	(자식 클래스)

// 오버라이딩 메서드
	flight(km : number){
		...}

}

재정의(오버라이딩)하기 위한 조건

  • 오버라이든(부모) 메서드 이름 === 오버라이딩(자식) 메서드 이름

&&

  • 오버라이든(부모) 타입 ≥ 오버라이딩(자식) 타입

&&

  • 오버라이든(부모) 매개변수 개수 ≥ 오버라이딩 메서드 매개변수 개수

안되는 거

//오버라이든 클래스
flight(km: number)

//오버라이딩 클래스
filght(cm : string)

=> 부모 타입이 더 넓거나 같아야 함 => flight(km: number | string)
=> 매개 변수 이름(km, cm) 달라도 상관 없음
//오버라이든 클래스
flight(km: number)

//오버라이딩 클래스
filght(cm : string, speed:number)

=> 부모 클래스 매개 변수가 더 많으면 안 됨, 부모가 더 많거나 같아야 함

예외 any

//오버라이든 클래스
flight(km: number)

// 오버라이딩 클래스
filght(km : any)

// any가 더 큰 타입이지만 어떤 타입이든 다 받을 수 있으므로 가능

2) 오버로딩

overloading 매서드의 이름은 같지만 매개변수의 타입, 개수를 다르게 정의하는 방법

  1. 메서드를 오버 로딩
class SingleTypeChecker {
	constructor()
	
// 오버라이든 메서드
	typeCheck(value:String) : void {
			console.log(오버라이든)
	}
} 

class UnionTypeChecker extends SingleTypeChecker {
	constructor() { super() }
	
// 오버로드
	typeCheck(value : number) : void;
	typeCheck(value : string) : void;
	
// 오버라이딩 메서드
	typeCheck(value : number | string) : void {...}

}

함수 이름은 같지만 매개 변수 선언 형태가 다른 형태

  1. 인터페이스를 클래스에서 구현, 오버로딩
interface Ipoint {
	getx(x:any) : any;
}

class Point implements Ipoint {
	getx(x?:number|string){
			if(typeof x === "number"){}
			if(typeof x === "string"){}
	}
}

인터페이스를 쓰면 선언 / 구현을 분리하고 구현부의 구조를 강제할 수 있음

⇒ interface (선언)

⇒ class (구현)

클래스를 상속하는 것보다 interface 를 이용하는 것이 복잡도가 낮음

2) 클래스와 인터페이스 기반 다형성 구현

다형성 여러타입을 받아들임으로써 여러 형태를 가지는 것

  1. 클래스의 다형성

→ 부모 클래스를 자식 클래스가 상속

→ 부모 클래스 a가 변수 타입으로 지정

→ 자식 클래스 객체에 할당 가능

→ 이때 자식 클래스가 받는 어떤 타입이든 부모 클래스가 받을 수 있음

  1. 인터페이스의 다형성

→ 인터페이스 a, a를 구현한 클래스 b

→ 클래스 b가 인터페이스 a타입으로 지정된 변수에 할당될 때

  1. 매개변수의 다형성

→ 메서드의 매개 변수가 여러 타입을 받아들이는 것 (서브 타입 타형성)

→ 타입을 지정하지 않고 여러 타입을 받아들이는 것 (매개변수 다형성)

  1. 클래스의 다형성
class Planet {
	pubilc diameter : number;
	protected isTrans : boolean = true;

	getIstrans () : boolean {
			return this.isTrans
	}
	
	stopTrans(): void {
		console.log("stop")
		this.isTrans = false
	}
}

class Earth extends Planet {
	pubilc feature : string[] = ["a","b","c"]
	
	stopTrans() : void {
			return this.trans = false
	}
}
let earth : Planet = new Earth()

earth.feature <= 접근 불가

earth.getIstrans() true

earth.stopTrans()  /* 오버라이딩 */ <- false

earth 변수는 new Earth() 를 할당 받더라도 실제 동작은 부모 클래스 기준으로 동작됨

⇒ 따라서 feature 접근 불가

⇒ 따라서 feature 접근 불가

오버라이든 메서드 보다 오버라이딩 메서드가 우선으로 호출됨

abstract class Train {
	constructor(protected speed : number){
		speedUp(): void {
				this.speed ++;
		}
	}

	abstract getSpeed(): number;
}

abstract Ktx extends Train {
	constructor(protected speed : number){
		super(speed)
	}

/* 오버라이딩, 자식에서 호출, 런타임 다형성 */
	pubilc getSpeed():number {
		return this.speed;
	}

	pubilc speedUpUp():number {
		return this.speed +=2;
	}
}
// 부모 클래스 할당
let ktx : Train = new Ktx(300)

// 오버라이딩
ktx.getSpeed();
=> 300

ktx.speedUp();
=> 301

ktx.speedUpUp()
=> 부모에서 동작하기 때문에 접근 불가
  1. 인터페이스 다형성
interface IPerson {
	height: number;
	getAlias: ()=>string;
	getAge() : number;
}

class PoliceOfficer implements Iperson {
	height: number;
	getAlias: ()=> "happy"
	getAge() : number {
		return 10;
	}
	hasCLub() {
		return true;
	}
}
let policeMan : Iperson = newPoliceOfficer();

policeMan.getAlias(); => happy
policeMan.getAge(); => 10
policeMan.hasClub(); => 접근 불가
  1. 매개변수 다형성

⇒ 유니언 타입

class Moniter {
	display(monitor : Led | Oled) {
			
	// if(typeof monitor === Led) {} 대신에
			if(monitor instanceof Led) {
				return console.log("led 모니터")
			}
			else (monitor instanceof Oled) {
				return console.log("Oled 모니터")
			}
	}
} 

타입이 늘어날 때마다

type MultiType = LED | Oled | Uhd

class Moniter {
	display(monitor : MultiType) {
...
}

로 쓰는 건 근본적인 해결책 아님

3-1. 인터페이스 타입을 이용한 매개변수의 다형성

interface Monitor {
	getName():string;
}

class Led implements Moniter {
	constructor(private name: string){
		getName(): string {return this.name}
	}
}

class Oled implements Moniter {
	constructor(private name: string){
		getName(): string {return this.name}
	}

class MoniterTest {
	display1(monitor : Moniter) {
		let myMoniter : Moniter = moniter;
		return myMonitor.getName();
	}
}

let displayTest = new MonitorTest()

displayTest.display1(new Led("LED TV")) => LED TV
displayTest.display1(new Oled("OLED TV")) => OLED TV
  • 구현 클래스 타입은 인터페이스 타입으로 타입 호환 ⇒ 유니언 타입 대신 인터페이스
  • instanceof 검사 안해도 됨 ⇒ 분기 처리/ 타입 가드 안해도 필요 없음

 

3) getter setter

getter 접근자

setter 설정자

class Student {
	// 객체를 통해 접근할 수 없도록 private
	private studentName :string;
	
	get name(): string {
		return this.studentName;
	}

	set name(name:string){
		if(name.indexOf("happy") !== 0){
			this.studentName = name;
		}
	}
}
let student2 = new Student()

student2.name = "happy"
=> set

student.name
=> "happy"
=> get

4) 정적 변수 / 정적 메서드

ts 는 strict 키워드 지원

클래스에 정적 변수 / 메서드 선언할 때 사용

class Circle {
  // 정적 변수
	static pi = 3.14
}

console.log(Circle.pi) 로 접근 가능

private static pi = 3.14
일시 접근 불가능

⇒ 공통으로 써야할 멤버가 있다면 static

4-1.싱글턴 패턴 적용

class Member {

	static age = 0;
	static getAge() {
		return this.age;
	}

	private constructor()

}
let member = new Member() 처럼 인스턴스 생성불가 => private

Member.age 로 접근 가능

static 사용하면 객체 생성 없이 접근 가능

⇒ 상태 정보 담을 수 있음

⇒ 인스턴스를 만들지 못해 외부에 변수를 둘 수 없음

⇒ 외부에 변수를 두면서 객체를 유지하게 하려면 싱글턴 패턴 도입해야함

싱글턴 패턴

유일한 객체를 생성해, 공유해서 사용하는 방식

싱글턴 패턴 (부지런한 초기화 / 게으른 초기화)

부지런한 초기화

class EagerLogger {
	private static uniqueObject : EagerLogger = new EagerLogger()
	
	// private 으로 객체 생성 안되게
	private EagerLogger(){}

	// static 을 붙여서 외부 접근 가능하게
	public static getLogger() : EagerLogger {
		return this.uniqueObject
	}

	// 정보 로그 출력
	public info(message :string) {
		console.log(`[info] ${message}`)
	}
}
// getLogger 를 통해 싱글턴 객체를 호출
// new 사용 불가 -> 같은 객체를 참고하고 있어서

let eagerLogger: EagerLogger = EagerLogger.getLogger();
eagerLogger.info("1번 : 경고")

=> [info] 1번 : 경고

부지런한 초기화

⇒ 프로그램이 구동할 때 초기화 일어남

⇒ 공개된 정적 메서드를 통해 생성된 객체를 얻음

⇒ 싱글턴 객체는 임이의 변수에 할당 되어 접근할 수 있음

게으른 초기화

class LazeLogger {
	
// 싱글턴 객체를 담는 정적 변수 선언
	private static uniqueObject : LazeLogger;

// private 을 붙여서 객체로 생성 못하게
	private LazeLogger(){}

	public static getLogger():LazeLogger {
	
// 새로 생성된 객체 없으면 초기화
		if(this.uniqueObject === null) {
				this.uniqueObject = new LazeLogger()
		}
			return this.uniqueObject;
	}

	public info(message:string){
			console.log(`[info] ${message}`)
	}
}
let lazeLogger22:LazeLogger = LazeLogger.getLogger();

게으른 초기화

⇒ 프로그램이 구동할 때 초기화 x

⇒ 공개된 정적 메서드를 호출하는 시점에 객체를 생성

초기화 시점에 따라 다를 뿐

둘다

private 정적 변수를 getter를 사용해

getter 자체를 외부에서 인스턴스를 만듬

 

5) readOnly 제한자

⇒ readOnly 선언된 변수는 초기화되면 재할당 불가능

특정 값을 읽기 전용으로 만들 때

let literal = {readonly alias :string} = {alias:"happy"}
// 객체 리터럴 속성 앞에 지정
// 초기화를 강제로 하지 않음 => 재할당 불가능
interface Icount {
	readonly count: number;
}

class TestReadOnly implements Icount {
	
	static readonly count: number;
	// 앞에 static, private, private 가능

	getCount(){
		this.count3 = 0; // 재할당 불가
		readonly count31 = 0; // 메서드 선언 불가
	}
}

function getCount () {
	readonly count: number; // readonly 함수에 선언 불가
}

 

 

 

 

 

728x90
반응형

'TIL' 카테고리의 다른 글

타입 표명 vs 타입 단언  (0) 2023.07.23
타입스크립트 제네릭  (0) 2023.07.23
클로저  (0) 2023.06.21
기명함수 / 익명함수  (0) 2023.06.21
api gateway  (0) 2023.06.06

댓글