[TypeScript] 클래스 & 인터페이스

HIHI JIN·2023년 3월 9일
0

typescript

목록 보기
5/10
post-thumbnail

타입스크립트 핸드북Udemy강의를 토대로 Typescript를 공부합니다.

클래스란 무엇인가

클래스 : 객체의 청사진
인스턴스 : 클래스를 기반으로 객체의 형태, 포함해야 하는 데이터, 필요한 메소드를 정의하는 것
객체 = 클래스 내의 인스턴스

객체 : 코드로 작업을 수행하면서 사용할 수 있는 구체적인 요소들로,
데이터를 저장하고 메소드를 실행하기 위해 메소드를 저장하는 데 사용하는 데이터 구조

클래스를 기반으로 하면 동일한 구조, 동일한 클래스를 기반으로 하는 동일한 메소드로 여러 객체를 빠르게 복제가능, 객체의 생성 속도 높여줌
객체에 저장된 정확한 데이터 세부 정보만 다를 뿐이다.

퍼스트 클래스 만들기

클래스 이름을 지정(Department)
관례상 클래스명의 첫글자는 대문자로 입력하기

name속성의 값 타입은 string으로 타입 지정

생성자 함수 : 초기값을 전달할 수 있는 함수

this 키워드로 name에 접근하고 생성자함수에서 받아온 n을 값으로 저장한다.
그러면 Department 객체가 생성될 때, name필드의 값을 n에서 얻게 된다.

new키워드를 사용하고 생성한 클래스명을 붙이고 실행하면 new Department객체가 만들어진다.
생성자 인수를 클래스명에 전달하면 생성자 인수는 생성자 함수로 전달되어 객체의 name키값이 바뀐다.

class Department {
	name : string;
	constructor(n: string){
    	this.name = n;
    }
}
const accounting = new Department('Accounting');
console.log(accounting); //Department {name : 'Accounting'}

생성자함수 및 "this"키워드

타입스크립트는 this가 무엇으로 참조되어야 하는지 인식한다.
describe가 실행될 때 describe 코드의 this는,
department 클래스에 기반한 인스턴스를 참조해야 한다.

accountingCopy의 경우,
accountingCopy에서 describe를 호출하면서 Department의 인스턴스에서 호출한 게 아니기 때문에 this에 위반된다.
this는 이 경우에 Department 타입의 객체를 참조하지 않기 때문에,
describe를 호출하는 객체인 accountingCopy에 name 속성을 따로 추가해주어야 한다.

class Department {
	name : string;
	constructor(n: string){
    	this.name = n;
    }
  describe(this: Department){
  	console.log("Department: " + this.name);
    //타입스크립트는 this가 무엇으로 참조되어야 하는지 인식한다.
    //describe가 실행될 때 describe 코드의 this는,
    //department 클래스에 기반한 인스턴스를 참조해야 한다.
    
    //accountingCopy의 경우,
    //accountingCopy에서 describe를 호출하면서 Department의 인스턴스에서 호출한 게 아니기 때문에 this에 위반된다.
    //this는 이 경우에 Department 타입의 객체를 참조하지 않기 때문에,
    //describe를 호출하는 객체인 accountingCopy에 name 속성을 따로 추가해주어야 한다.
  }
}
const accounting = new Department('Accounting');
console.log(accounting); //Department {name : 'Accounting'}

accounting.describe(); //Department: Accounting
//new Department객체를 생성하고 객체의 name키값은 accounting ⭐
//describe메소드의 this.name은 new Department객체의 this.name을 참조한다.⭐

const accountingCopy = {name: "Dummy", describe: accounting.describe};
//name속성 추가!
accountingCopy.describe(); //Department: Dummy

public/private 엑세스 수정자

private + 속성 : 클래스, 즉, 생성된 객체 내부에서만 접근할 수 있는 속성이 되었다는 것
따라서 Department 클래스 내의 어떤 메소드로든 그 속성에 접근할 수 있지만, 외부에서는 접근 하면 에러 발생
public 속성 : 외부에서 접근가능

class Department {
	public name : string; //public 기본값
  	private employees: string[] = [];
  //employees속성에 private 추가⭐
	constructor(n: string){
    	this.name = n;
    }
   describe(this: Department){
  	console.log("Department: " + this.name);
   }
  addEmployee(employee: string){
  	this.employees.push(employee);
    // addEmployee 메서드를 이용해서 employees배열에 요소 추가하기⭐
  }
  printEmployeeInformation(){
  	console.log(this.employees.length);
    console.log(this.employees);
  }
}
const accounting = new Department('Accounting');
console.log(accounting); //Department {name : 'Accounting'}

accounting.addEmpolyee("Max"); //직원 추가⭐
accounting.addEmpolyee("Anna");
accounting.printEmployeeInformation();//직원 정보

//accounting.employees[2] = "Manu";⭐
//error! 외부에서 private 속성에 직접 접근해서 바꾸려고 하면 에러⭐ 
//보다 복잡한 애플리케이션을 구축할 때에는, 클래스를 사용하는 방법은 확실한 한 가지로 정하고 다른 방법은 사용하지 않도록 해야 한다.⭐

약식 초기화

대부분의 사용 사례에서 모든 속성과 필드가 생성자에서 초기화되는 클래스가 많이 사용되므로,
필드를 찾은 다음 값을 저장해야 하는 이중 초기화 코드를 한 번에 처리하도록 축약 할 수 있다.
이중 초기화 코드 대신 속성 정의와 생성자함수 코드 블록의 내용을 제거하면 된다.
그리고 접근 제어자(public/private)를 매개변수 앞에 추가하면 된다.
(public을 굳이 추가해야 하는 이유는,
단순히 생성자에서 인수들을 가져올 뿐만 아니라 이 클래스에 대해 정확히 동일한 이름으로 속성을 만들고 싶다고
타입스크립트에게 알리는 명시적인 명령이기 때문이다.)

생성자가 취할 인수를 정의하면 이 앞에서 접근 제어자를 지닌 모든 인수에 대해 동일한 이름의 속성이 생성되고,
인수에 대한 값이 생성된 속성에 저장된다.

class Department {
	//public name : string;
  	//private employees: string[] = []; 
	constructor(private id: string, public name: string){
    	//this.name = n;
      	//this.id =id;
    }
   describe(this: Department){
  	console.log(`Department (${this.id}): ${this.name}`);
   }
  addEmployee(employee: string){ 
  	this.employees.push(employee); 
  }
  printEmployeeInformation(){
  	console.log(this.employees.length);
    console.log(this.employees);
  }
}
const accounting = new Department("b1",'Accounting'); //생성자에 새 인수를 추가해야 한다.
accounting.describe(); //Department (b1): Accounting

accounting.addEmpolyee("Max");
accounting.addEmpolyee("Anna");
accounting.printEmployeeInformation();

"읽기전용 속성"

초기화 후에 변경되어서도 안 되는 특정 필드가 있는 경우,
확실히 변경되지 않게 하려면 readonly 추가 -> (private + readonly + 속성)
특정 속성이 초기화되고나면 이후에는 변경되어서는 안 된다라는 의미로
클래스 내 다른 곳에서 변경하려고 하면 에러 발생!

상속

전체 부서의 it부서를 만든다고 할 때, name, id, employees은 전체부서(Department class)에서 가져와도 될 것이다.
extends 키워드 사용!

class Department {
	//public name : string;
  	//private employees: string[] = []; 
	constructor(private id: string, public name: string){
    	//this.name = n;
      	//this.id =id;
    }
   describe(this: Department){
  	console.log(`Department (${this.id}): ${this.name}`);
   }
  addEmployee(employee: string){ 
  	this.employees.push(employee); 
  }
  printEmployeeInformation(){
  	console.log(this.employees.length);
    console.log(this.employees);
  }
}

class ITDepartment extends Department{
//⭐
}
const accounting = new ITDepartment("b1",'Accounting');

ITDepartment 클래스 내용이 비어있어도 생성자를 호출할 수 있고 새 객체를 만들 수 있다.
다른 클래스로부터 상속된 클래스는 생성자를 포함하여 상속하는 클래스가 가진 모든 것을 자동으로 가져온다.
상속받은 클래스에 고유한 생성자를 추가하지 않는다면 상속받은 클래스를 인스턴스화 할때 상속하는 클래스의 생성자가 자동으로 사용된다.


ITDepartment에 생성자를 추가할 때는,
super 키워드로 생성자에서 받아올 속성을 적어주면 된다.
super는 기본 클래스의 생성자를 호출한다.
부모클래스에서 받아온 id속성에 생성자 인수를 넣는다면 그대로 속성을 적어주고,
부모클래스에서 받아온 name속성에 생성자인수를 안 넣는다면 기본값을 넣어준다.

class ITDepartment extends Department{
  	admins: string[];
  //⭐ITDepartment의 고유의 특수한 속성을 추가할수도 있다.
	constructor(id: string, public admins: string[]){
    	super(id, 'IT');
      	this.admins = admins;
    }
  
}
const accounting = new ITDepartment('d1',['Max']);
//생성자에 id와 admin 인수를 전달한다.
accounting.describe; //ITDepartment (d1): IT

속성 및 보호된 수정자 재정의

private 속성은 정의된 클래스 내에서만 접근 가능하며 해당 클래스로부터 상속받는 클래스에서는 불가능하므로
employees는 Department 기반의 클래스가 아닌 Department 내에서만 사용 가능하다.
부모 클래스의 employees속성을 private -> protected로 바꾸면 private처럼 아예 외부에서는 접근 불가능하지만 상속받는 클래스내에서도 접근 가능하게 만든다.

class Department {
  	protected employees: string[] = []; //⭐
	constructor(private id: string, public name: string){
    	//this.name = n;
      	//this.id =id;
    }
   describe(this: Department){
  	console.log(`Department (${this.id}): ${this.name}`);
   }
  addEmployee(employee: string){ 
  	this.employees.push(employee); //this.employees 접근 가능⭐
  }
  printEmployeeInformation(){
  	console.log(this.employees.length);//this.employees 접근 가능⭐
    console.log(this.employees);//this.employees 접근 가능⭐
  }
}

게터 & 세터

게터 : 값을 가지고 올 때 함수나 메소드를 실행하는 속성으로 개발자가 더 복잡한 로직을 추가할 수 있게 한다.
게터 : get을 이용하고 무언가 반환하도록 작성해야 한다.
세터 : set을 이용
게터는 값을 반환, 세터는 값을 추가

class AccountingDepartment extends Department{
  private lastReport: string;
  //lastReport 속성이 private이므로 this.을 통해서 접근 불가⭐
  
  //게터 : lastReport를 반환하는 메소드⭐
  //이 코드 블록은 이제 공개적으로 접근 가능하고 속성처럼 사용하면 된다.⭐
  get mostRecentReoprt(){
    if(this.lastReport) return this.lastReport; //lastReport가 정의되있다면 반환⭐
    throw new Error('No report found.');
  }
  
  set mostRecentReport(value: string){
    //세터를 addReport의 대체방안으로 사용할 수 있다.⭐
    //메소드가 아니고 값을 할당하는 방법으로 value를 addReport에 전달할 수 있다.⭐
    if(!value) return new Error('Please pass in a vaild value!')
  	this.addReport(value);
  }
  
	constructor(id: string, private reports: string[]){
    	super(id, 'Accounting');
      	this.lastReport = reports[0]; //reports 속성으로 초기 설정, 빈reports배열을 전달하면 정의되지 않는다.⭐
    }
  addReport(text: string){
  	this.reports.push(text)
    //this.lastReport = text; //lastReport 속성이 private이므로 this.을 통해서 접근 불가⭐
  }
  printReports(){
    console.log(this.reports)
  }
}

const accounting = new AccountingDepartment('d2', []); //초기 report는 빈값⭐

accounting.addReport("something"); //report배열에 push⭐

//게터 기능! 값을 반환
console.log(accounting.mostRecentReport); //"something"⭐
//게터에서 mostRecentReport에서 반환하는 건 lastReport, lastReport는 report배열의 0번째 인덱스⭐

//세터 기능! 값을 추가
accounting.mostRecentReport="year end Report"; //["year end Report","something"]⭐

정적 메서드 & 속성

(static + 속성 / static + 메소드)
정적 메소드와 속성을 사용해서 클래스의 인스턴스에서 접근할 수 없는 속성과 메소드를 클래스에 추가할 수 있다.
new 클래스 이름을 먼저 호출하지 않고 클래스에 직접 접근하는 것!

Math가 정적 메소드와 속성의 일반적인 사용 사례이다.
자바스크립트에 내장된 함수 중 Math()함수는 인스턴스에서 접근할 수 없는 메소드와 속성이므로
new Math를 호출할 필요가 없고, 직접 클래스 자체에서 속성과 메소드에 접근해야 한다.

class Department {
  	//정적 속성 추가⭐
  	static fiscalYear = 2020;
  
  	protected employees: string[] = []; 
	constructor(private id: string, public name: string){
    
  //이 클래스를 인스턴스화 하지 않고 접근할 수 있는 정적 메소드로 만들려면,⭐
  //이 메소드 앞에 정적 키워드를 추가한 다음 객체를 반환해야 한다.⭐
  //이 메소드를 사용할 때 name속성의 값을 전달인자로 넘겨줘야 한다.⭐
  static createEmployee(name: string){
    return {name: name};
  }
   describe(this: Department){
  	console.log(`Department (${this.id}): ${this.name}`);
   }
  addEmployee(employee: string){ 
  	this.employees.push(employee); 
  }
  printEmployeeInformation(){
  	console.log(this.employees.length);
    console.log(this.employees);
  }
}
const employee1 = Department.createEmployee("Max"); //⭐
console.log(employee); //{name: "Max"} ⭐
console.log(Department.fiscalYear); //2020⭐

추상 클래스

(자식클래스는 부모클래스의 모든 속성과 메소드를 접근할 수 있고, 자식 클래스는 메소드를 재정의할 수도 있다.
자식클래스에서 재정의하는 메소드에서 부모클래스의 속성을 사용하려면 private이 아닌 protected여야 접근가능하다.)

abstract 메소드 ?
추상 메소드를 쓴다면 빈 메소드를 부모클래스에 입력하고 모든 자식 클래스에 이 메소드를 추가하고 재정의 해야 한다.
부모클래스에는 메소드의 형태와 메소드의 구조가 어떤 것인지를 정의, 그 외에는 아무것도 정의하지 않는다.
메소드 앞에 abstract가 있는 메소드가 하나 이상이라면 클래스 앞에도 abstract를 추가해야 한다.

abstract 클래스 ?
추상 클래스는 상위 클래스를 기반으로 하는 모든 클래스가 공통 메소드 또는 속성을 공유하도록 하려는 경우 유용하다.
따라서 abstract 키워드로 표기된 클래스들은 자체적으로 인스턴스화할 수 없고, 기본적으로 상속되어야 할 클래스일 뿐이다.
상속되는 클래스가 인스턴스화되고 구체적인 구현을 제공하도록 할 수 있다.
상속되는 클래스에는 메소드를 재정의할 때 코드블록에는 원하는 무엇이든 입력할 수 있다.

abstract class Department {
  ...
abstract describe(this: Department): void;
}
//이 메소드의 형태와 메소드의 구조가 어떤 것인지를 정의, 그 외에는 아무것도 정의하지 않음

class ITDepartment {
  ...
describe(){
  	console.log('IT');
  }
}//모든 자식 클래스에서 메소드를 재정의해야 하고 코드블록에는 원하는 무엇이든 입력할 수 있다.

싱글톤 & 개인 생성자

싱글톤 패턴 : 객체지향프로그래밍에 있으며 특정 클래스의 인스턴스를 정확히 하나만 갖도록 한다.
이 패턴은 정적 메소드나 속성을 사용할 수 없거나 사용하지 않고자 하는 동시에 클래스를 기반으로 여러 객체를 만들 수는 없지만 항상 클래스를 기반으로 정확히 하나의 객체만 가질 수 있도록 하고자 하는 경우에 유용하다.
(싱글톤 클래스는 “new”로 생성하지 않고 메소드를 호출하여 구성하므로 특정 시점에 반드시 단 하나의 클래스 인스턴스가 존재합니다.)
ex) 회사 전체에 IT 부서는 하나 이상일 수 있지만 회계 부서는 하나만 있다.
new AccountingDepartment를 여러 번 수동으로 호출하지 않도록 하기 위해 AccountingDepartment의 생성자함수 앞에 private 키워드를 붙여 private 생성자로 바꿀 수 있다.
생성자가 private으로 지정되면 클래스 내에서만 접근이 가능하므로, 클래스 자체에서 정적 메소드를 호출해야 한다.

class AccountingDepartment extends Department{
	private static instance: AccountingDepartment;//AccountingDepartment타입이 될 instance 호출하고, 여기에 AccountingDepartment 인스턴스가 저장되도록 한다.
  
  static getInstance(){ //이 클래스의 인스턴스가 이미 있는지 확인하고 없다면 새 인스턴스를 반환한다.
  	if(AccountingDwpartment.instance) return this.instance; //이미 인스턴스를 가지고 있는 경우
    this.instance = new AccountingDepartment("d2", []);//없다면 새로운 인스턴스를 생성
    return this.instance;
  }
}

const accounting = AccountingDepartment.getInstance(); //AccountingDepartment의 새 인스턴스가 반환된다.

첫번째 인터페이스

인터페이스 : 객체의 구조를 설명한다.
interface 키워드로 인터페이스를 생성한다.(js에는 없고 ts에만 있는 기능)
클래스와 마찬가지로 첫글자는 대문자(관례)
interface의 코드 블록 내에서 Person객체의 형태를 정의할 수 있다.
클래스와 달리 인터페이스는 청사진으로 사용 X, 사용자 정의 타입으로 사용한다.

인터페이스의 개념은 객체의 타입을 확인하는 데 사용할 수 있다.

interface Person{
	name: string; //쌍반점
  	age: number;
  //구체적인 값을 지정할 수 없다. 기본값을 지정하려 하면 인터페이스가 초기자를 가질 수 없다는 에러 발생
 //구체적인 값이 아닌 구조만 있을 수 있다.
  
  	greet(phrase: string): void; //인수의 이름, 타입, 메소드 반환 타입 순서(매개변수는 없어도됨)
  //메소드도 실제 메소드를 추가하는 것이 아닌 구조와 어떤 형태여야 하는지 설명을 추가하여, Person 객체가 가질 메소드를 정의한다.
}
let user1: Person;
user1 = {
	name: "Max",//쉼표
  	age: 30,
  	greet(phrase: string){
    	console.log(phrase + " " + this.name);
    }
};//user1은 인터페이스 정의를 충족하기 때문에 이제 유효한 객체이다.

user1.greet("Hi there - I am"); //Hi there - I am Max
//설정한 greet 메소드에서 출력하는 메세지이다.
//인터페이스는 이 구조를 가져야 하는 객체에 대한 타입을 확인하는 타입으로 사용한다.

클래스와 인터페이스 사용하기

interface를 type으로 바꾸더라도 에러없이 작동한다.
하지만 둘이 완전히 같지는 않다.
인터페이스는 객체의 구조를 설명하기 위해서만 사용한다.
사용자 정의 타입으로도 가능한 작업은 클래스 내에 인터페이스를 구현하는 것이다.
작업 중 인터페이스를 자주 사용하는 이유는 클래스가 인터페이스를 이행하고 준수해야 하는 약속처럼 사용할 수 있기 때문이다.

interface Greetable{
	name: string;
}

//Person 클래스를 추가
//타입스크립트에게 이 클래스가 기본적으로 이 인터페이스를 준수해야 한다고 알려줘야 한다.
//클래스 이름 뒤에 implements키워드 + 인터페이스 이름
//여러 개의 인터페이스를 구현할 수 있다.(상속과의 차이점)
//상속은 한 클래스로부터만 상속하고, 인터페이스는 쉼표로 구분하여 여러 개를 구현할 수 있다.
class Person implements Greetable{
	name: string;
  
  constructor(n: string){
  	this.name = n;
  }
  greet(phrase: string){
  	console.log(phrase + " " + this.name);
  }
}

let user1: Greetable;
//Greetable로 취급되어야 하는 모든 객체는 이름과 greet 메소드를 지닌 객체여야 한다.
//user1 변수는 Greetable 객체를 가져야 한다.
//이 인터페이스를 준수하는 모든 클래스가 모든 클래스가 name 클래스와 greet 메소드를 갖도록 해야 한다.

user1 = {
	name: "Max",//쉼표
  	age: 30,
  	greet(phrase: string){
    	console.log(phrase + " " + this.name);
    }
};

인터페이스 vs 추상 클래스
인터페이스는 주로 구체적인 구현이 아닌 서로 다른 클래스 간의 기능을 고유하기 위해 사용된다.
인터페이스 내에 구현이나 값을 입력하는 게 아닌 구조와 클래스가 가져야 할 기능을 입력해야 한다.
추상 클래스로 작업하는 것과 다소 비슷하기 때문에,
인터페이스에는 구현 세부 사항이 전혀 없는 반면,
추상 클래스는 여러분이 덮어써야 했던 부분과 제가 수행한 구체적 구현 부분을 혼합할 수 있다.

let user1: Greetable;
//let user1: Person; //타입을 Person으로 설정해도 오류X(user1에 저장된 person객체는 결국 Greetable인터페이스에 기반한 것이기 때문)
user1 = new Person("Max"); //인터페이스를 구현하는 클래스를 기반으로 하며 인터페이스를 타입으로서 사용할 수 있다
user1.greet("Hi there - I am");
console.log(user1); //Person {age: 30, name: "Max"}
};

인터페이스의 또다른 기능으로,
인터페이스를 어떤 상수나 변수의 타입으로 사용하여 인터페이스 타입을 기반으로 하는
다른 타입의 다른 클래스를 저장할 수도 있다.

왜 인터페이스인가

interface Greetable{
	name: string;
  greet(phrase: string): void;
}//클래스가 greet인 메소드를 가지고 있고 다른 클래스도 가지고 있는지 확인하고자 할 때, 이 메소드가 존재하게 해주는 인터페이스를 구현하면 된다.
//클래스 간에 기능을 쉽게 공유할 수 있는데 모든 클래스는 메소드가 호출될 때 실행되어야 하는 정확한 코드, 즉, 고유한 구현을 추가해야 한다.

읽기전용 인터페이스 속성

인터페이스 내에 readonly 제어자도 추가할 수 있지만, public, private 등은 지정할 수 없다.
readonly를 속성에 추가하면 인터페이스를 기반으로 구축하는
모든 객체의 속성이 한 번만 설정되어야 하며 이후에는 읽기 전용으로 설정하여 객체가 초기화되면 변경할 수 없도록 할 수 있다.

인터페이스를 클래스에 구현하고 나면 클래스는 readonly를 추가하지 않아도 인터페이스의 영향을 받으므로 그 속성이 읽기전용임을 자동으로 추론한다.

인터페이스 확장하기

여러 인터페이스를 하나의 인터페이스로 병합할 수 있도록 둘 이상을 확장할 수 있다. 인터페이스를 클래스에 구현할 때 다른 인터페이스가 있다면 쉼표를 사용하여 구분할 수 있다.

클래스의 경우는 하나의 클래스만 상속가능하다.
인터페이스는 여러 인터페이스로부터 상속받을 수 있다!
(결국 모두 함께 병합되기 때문)

interface Named {
	readonly name: string;
}
//Greetable인터페이스가 Named 인터페이스를 확장하여 Greetable을 기반으로 하는 모든 객체가 greet 메소드와 함께 name도 가질 수 있도록 새로운 인터페이스를 형성한다.
interface Greetable extends Named{
	greet(phrase: string): void;
}
//인터페이스를 여러개 상속 받을 수 있다.
//greetable 인타페이스만 상속받으면 name 속성이 없으므로 오류 발생!
class Person implements Greetable, Named {
	name: string;
  constructor(n:string){
  	this.name = n;
  }
  greet(phrase:string){
  	console.log("greet")
  }
}

선택적 매개변수 & 속성

인터페이스의 name속성을 문자열로 정할거지만
인터페이스 기반의 모든 클래스의 name속성을 문자열로는 설정할지의 여부를 선택할 수 있다. -> 선택적 속성

타입스크립트는 이 속성이 인터페이스를 구현하는 클래스 내에 있을 수 있지만 반드시 그렇지는 않다고 인식
그 속성이 문자열이 아니어도, 클래스에 없어도 에러 발생 X, 선택 속성이기 때문!

클래스에서도 선택적 속성을 만들 수 있다.
생성자함수의 인수에 아무것도 들어오지 않는다면 인수를 값으로 하는 속성도 값을 얻지 못하므로 에러가 발생할 수 있지만,
생성자 함수의 매개변수를 선택적 매개변수로 바꾸고, 그 속성을 선택적 속성으로 만들면 에러 발생 x

interface Named {
	readonly name?: string;
  	outputName?: string; //선택 속성
}

interface Greetable extends Named{
	greet(phrase: string): void;
}

class Person implements Greetable, Named {
	name?: string;
  constructor(n?:string){ //n에 대한 값을 없지 못한다를 가정했을 때 name속성도 선택적이어야 하므로 물음표로 클래스에 선택속성을 만들고, 인터페이스에도 name을 선택 속성으로 만든다.
    //또는 n에 기본값을 설정해줄 수도 있다.
    
    //n이 있을 때만 name의 값을 n으로 준다.(n: string="")
    if(n){
    	this.name = n;
    }
  }
  //n이 있고 name이 있을 때의 경우, 없을 때의 경우를 만들어 준다.
  greet(phrase:string){
    if(this.name){
    	console.log(phrase+" "+this.name);
    }
  	console.log("Hi");
  }
}
profile
신입 프론트엔드 웹 개발자입니다.

0개의 댓글

관련 채용 정보