class Person {
name: string; // 할당되지 않아 초기화 오류 발생.
age!: number; // 할당되지 않아 초기화 오류가 있더라도 다른 곳에서 할당하기 때문에 넘어간다는 표시.
}
strict 모드에서는 프로퍼티를 선언하는 곳 또는 생성자에서 값을 할당해야 한다.
클래스의 프로퍼티가 정의되어 있지만, 값을 대입하지 않으면 undefined 이다.
생성자에는 async 를 설정할 수 없다.
tsconfig.json 에 strict 옵션을 끄면 초기화 오류가 표시되지 않는다.
초기화 오류를 표시해주지 않아서 그냥 넘어간다면 초기화 되어있지 않아 undefined 이므로 오류가 발생한다.
class Person {
name: string;
age!: number;
constructor(name: string){
this.name = name;
}
}
객체의 기본 상태를 설정해주는 생성자 메서드 constuctor()
constructor를 활용하여 설정해주면 초기화 오류가 발생하지 않는다.
constructor에는 비동기적인 처리를 위해 async 를 붙일 수 없다.
class 안에 메서드에 async 를 붙여 비동기 처리를 하도록 한다.
Javascript 에서는 Access Modifiers 를 제공하지 않는다.
( 암묵적으로 _ 를 활용하여 외부에서 사용하지 않겠다는 컨벤션만 존재한다.)
접근 제어자에는 public, private, protected 가 있다.
TypeScript는 기본적으로 모두 외부에서 접근이 가능하다.(public)
TypeScript class 내부 모든 곳에 접근 제어자 설정 가능.
접근 제어자 private 는 외부에서 호출할 수 없도록 한다.
class Person {
private name: string;
public age!: number;
constructor(name: string){
this.name = name;
}
}
코드량이 줄어든다.
public을 붙여주면 this.name = name; 으로 다시 할당문을 적어줄 필요없이 name 인자가 name 에 할당된다.
class Person {
public constructor(public name: string, public age: number){}
}
const p1: Person = new Person("Mark", 39);
console.log(p1); // { name:"Mark", age:39 };
class Person {
public constructor(public name: string, public age: number){}
}
const p1: Person = new Person("Mark", 39);
console.log(p1.name); // "Mark"
class Person {
public constructor(private _name: string){}
// 출력(내용을 가져간다.)
get name(){
return this._name + "lee";
}
// 입력(내부에 접근하여 내용 변경)
set name(n: string){
this._name=n;
}
}
class Person {
public readonly name: string = "Mark";
private readonly country: string = "Korea";
public constructor(private _name: string){}
hello(){
~~this.country ="China";~~ // Error! readonly는 다른곳에 바꿀수 없다.
}
}
class Students {
[index: string]: string;
// property 이름이 string이고 property 값도 string 이다.
}
class Students {
[index: string]: "male" | "female";
// property 이름이 string이고 property 값이 "male" 이거나 "female" 이다.
}
object 를 생성하지 않고 class 로 바로 사용하기
데이터가 공유된다.
class Person {
private static CITY = "Seoul";
public static hello() {
console.log("안녕하세요", Person.CITY);
}
}
Person.hello(); // 안녕하세요Seoul
static의 활용.
singleton petern ( 단일 객체 패턴 )
class ClassName {
private static instance: ClassName | null = null;
public static getInstance(): ClassName {
// ClassName 으로부터 만든 object 가 있으면 그걸 리턴
// 없으면, 만들어서 리턴
if ( ClassName.instance === null ) {
ClassNmae.instance = new ClassName();
}
return ClassName.instance;
}
private constructor() {}
}
const a = ClassName.getInstance();
const b = ClassName.getInstance();
console.log( a===b ) // true
class Parent {
constructor(protected _name: string, private _age: number) {}
public print(): void {
console.log(`이름은 ${this._name}이고, 나이는 ${this._age}입니다.`);
}
protected printName(): void {
console.log(this._name, this._age);
}
}
const p = new Parent('Mark', 30);
class Child extends Parent {
public gender = "male";
constructor(age: number){
//super 이용해 먼저 부모의 프로퍼티를 받아와 줘야 오류가 없다.
super("Mark Jr",age);
this.printName();
}
}
const c = Child(1);
c.print();
abstract class AbstractPerson {
protected _name: string = "Mark";
//구현하지 않은 빈 메소드를 만든다.
abstract setName(name: string):void;
}
// implement inherited
class Person extends AbstractPerson {
setName(name:string): void {
this._name = name;
}
}
const p = new Person();
p.setName('Mark');
function helloGeneric<T>(message: T): T {
return message;
}
any는 아무거나로 이후 생길 오류에 취약하다.
any로 계속 전달된다.
generic은 추론되어 올바르게 사용된다.
function helloGeneric<T>(message: T): T {
return message;
}
helloGeneric("Mark").length; // "Mark" type (string type 하위)
helloGeneric(39); // 39 type (number type 하위)
helloGeneric(true); // true type
// 여러개 generic 설정
function helloGeneric<T, U>(message: T, comment: U): T {
return message;
}
// 지정해주기
helloGeneric<string, number>("Mark", 39); // string type, number type
// 안넣으면 추론.
helloGeneric(39, 29); // 39 type, 29 type
function helloGeneric<T>(message: T[]): T {
return message[0];
}
helloGeneric(["hello","world"]); // string type
helloGeneric(["hello",5]); // string | number union type
function helloTuple<T,K>(message: [T,K]): T {
return message[0];
}
helloTuple(["hello","world"]); // hello type, world type
helloTuple(["hello",5]); // hello type, 5 type
type HelloFunctionGeneric1 = <T>(message: T)=>T;
const helloFunction1: HelloFunctionGeneric1 = <T>(message: T): T =>{
return message;
};
interface HelloFunctionGeneric2 {
<T>(message: T):T;
}
const helloFunction2: HelloFunctionGeneric2 = <T>(message: T): T =>{
return message;
};
class Person<T,K> {
private _name: T;
private _age: K;
constructor(name: T, age: K){
this._name = name;
this._age = age;
}
}
new Person("Mark", 29);
new Person<string, number>("Mark", 29);
generic 도 상속으로 사용할 수 있다.
generic 에 직접 상속.
class PersonExtends<T extends string | number> {
private _name: T;
constructor(name: T){
this._name = name;
}
}
type 최소한의 범위로 설정하는것이 오류를 막는다.
const person: IPerson = {
name: "Mark",
age: 39,
};
function getProp<T, K extends keyof T>(obj: T, key: K): T[K] {
return obj[key];
}