728x90
728x90
 

typescript class

1. OOP(객체 지향 프로그래밍)을 위한 초석

관련있는 변수나 함수, 데이터를 묶어놓는 틀을 class라 한다. 즉, object를 만드는 청사진(설계도)라 할 수 있다. class안에서도 내부적으로 보여지는 변수와 밖에서 보일 수 있는 변수를 나누어서 캡슐화encapsulation 할 수 있고 상속과 다양성이 일어날 수 있는 이러한 모든 것들이 가능한 것이 객체 지향 언어다.

*OOP : 객체의 관점에서 프로그래밍 하는 것

 

2. TypeScript에서는 클래스도 사용자가 만드는 type의 하나

 

3. JavaScript도 ES6부터 class를 사용 가능하나 접근제어자는 불가능하다.

 

4. class가 존재하기 이전

object를 만드는 기본적인 방법은 function이었다. 아래와 같이 new키워드로 불러왔음

function Book(type, author) {
    this.type = type;
    this.author = author;
    this.getDetails = function () {
        return this.type + " written by " + this.author;
    }
}

var book = new Book("Fiction", "Peter King");

console.log(book.getDetails());

 

 

(class 선언 예제)

class Person {
  name;
  
  constructor(name: string) {
    this.name = name;
  }
  
  speak() {
  	console.log(`I'm ${this.name}!!!`);
  }
}

const p1 = new Person("siot");

console.log(p1);
console.log(p1.name);
p1.speak(); // I'm siot
  • class이름의 첫 문자는 보통 대문자를 이용한다.
  • prototype을 베이스로 하는 문법상의 편리함을 제공
  • new를 이용하여 class를 통해 object 를 만들 수 있다.
  • constructor를 이용하여 object를 생성하면서 값을 전달할 수 있다.
  • this를 이용해서 만들어진 object를 가리킬 수 있다.
  • 컴파일 옵션 target:ES5 의 경우 컴파일되면 function으로 변경된다. ES6이후부터는 class그대로 변환된다.

 


constructor & initialize


class속성의 타입을 지정만 하고 초기화하지 않으면(초기값을 할당하지 않으면) 최종적으로 실행되는 타입을 알 수 없음

class Person {
  name: string = "Siot";
  age!: number;
}

const p1 = new Person(); // 생성자를 구현하지 않을 때는 default생성자라 하여 인자를 적지 않는다.)

console.log(p1); // Person {name: "Siot"}
console.log(p1.age); // undefined

class초기값 할당

class Person {
  name: string = "siot";
  age: number;
  
  constructor(age?: number) {
  	if (age === undefined) {
    	this.age = 1;
    } else {    
  	this.age = age;
  	}
}

const p1: Person = new Person(99);
const p2: Person = new Person();

console.log(p1);
  • 생성자 함수가 없으면, 디폴트 생성자가 불린다.
  • 프로그래머가 만든 생성자가 하나라도 있으면, 디폴트 생성자는 사라진다.
  • strict 모드에서는 프로퍼티를 선언하는 곳 또는 생성자에서 값을 할당해야 한다.
  • 프로퍼티를 선언하는 곳 또는 생성자에서 값을 할당하지 않는 경우에는 ! 를 붙여서 위험을 표현한다.
  • 클래스의 프로퍼티가 정의되어 있지만, 값을 대입하지 않으면 undefined이다.
  • 생성자에는 async를 설정할 수 없다.

 


Access Modfiers 접근 제어자


class Person {
  public name: string = "siot";
  private _age: number;  
}
  • typescript 속성, 생성자, 메서드는 접근 제어자를 붙여 외부 혹은 내부에서 접근이 가능하도록 설정할 수 있다.
  • 접근 제어자에는 public, private, protected가 있다. class내부의 모든 곳 (프로퍼티, 생성자, 메서드)에서 설정 가능
  • public: default. 외부에서 접근 가능하도록 설정하는 접근 제어자
  • private: 클래스 외부에서 접근할 수 없다. private을 지원하지 않는 javascript에서는 통상적으로 프로퍼티나 메서드 이름 앞에 _를 붙여 명시적으로 표현해왔다. 
  • protected: 외부에서는 불가능하나 상속관계에서는 접근 가능 

 

 


Initialization in constructor parameters

생성자의 매개변수를 받아 class의 속성으로 초기화


class Person {
  public constructor(public name: string, public age: number) {}
}

const p1: Person = new Person("Siot", 9);
console.log(p1);

중복되는 불필요한 과정과 코드를 제외하고 생성자의 매개변수를 받아서 class의 속성으로 초기화하는 방법

consturctor의 매개변수의 각각의 앞에 접근제어자를 설정할 수 있다.

 

 


Getters & Setters📌


class에서 getter와 setter를 활용하는 방법

예제 1

class Person {
  public constructor(public _name: string, public age: number) {}

  get name() {
    console.log('get');
    return this._name + " Mountain";
  }

  set name(n: string) {
    console.log('set');
    this._name = n;
  }
}

const p1: Person = new Person("Siot", 9);
console.log(p1.name); //get 꺼내옴, get을 하는 함수 getter
p1.name = 'kim'; // set 새로운 값을 할당, set을 하는 함수 setter
console.log(p1.name);

// get
// Siot Mountain
// set
// get
// kim Mountain

예제 2

class User {
	constructor(firstName, lastName, age) {
    	this.firstName = firstName;
        this.lastName = lastName;
        this.age = age;
    }
    
    get age() {
    	return this._age;
    }
    
    set age() {
    	// if (value < 0) {
        // 	throw Error('age can nt be negative');
        // }
    	this._age = value < 0 ? 0 : value;
    }
}

const user1 = new User('siot', 'kim', -1); //나이를 마이너스로 적는 오류를 범했다면?
console.log(user1.age); // 0, setter에서 값을 바로 잡아줌

🎂 Uncaught RangeError : Maximum call stack size exceeded!

  ㄴ _age와 같이 이름을 변경해주는 이유

age라는 getter를 정의하는 순간 this.age는 메모리에 올라가있는 데이터를 읽어오는 것이 아니라 바로 getter를 호출하게 된다. 그리고 setter를 정의하는 순간 this.age에 age값을 할당할 때 바로 메모리에 할당하는 것이 아니라 setter를 호출하게 된다. setter안에서 전달된 value를 this.age에 할당할 때 메모리의 값을 업데이트하는 것이 아니라 setter를 호출하게 된다. setter로 돌아와서 내부 코드는 또다시 setter를 호출하며 무한반복되어 콜스택이 차는 오류가 발생한다. 이것을 방지하기 위해서는 gettersetter에서 사용하는 변수의 이름을 변경시켜주면 된다. 통상적으로 이름 앞에 언더바를 붙인다. 

-> 위 예제에서 field는 firstName, lastName, _age 이지만 .age로 호출할 수 있는 것은 내부적으로 getter와 setter를 이용하기 때문이다.

 

 

 


readonly properties


  • public + readonly일 경우 외부에서 새로운 값을 할당 할 수 없다.
  • private + readonly일 경우 constructor 안에서만 할당 가능하다.
class Person {
  public readonly name: string = 'siot';
  private readonly country: string;

  public constructor(public _name: string, public age: number) {
    this.country = "Korea";
  }

  hello() {
    this.country = "USA" // error
  }
}

const p1: Person = new Person("Siot", 9);
console.log(p1.name); 
p1.name = "ieoung";  // error

 

 


index Signatures in class

캐릭터 별로 사용가능한 기술들을 묶고 싶을 때 인덱싱해서 동일한 형태로 묶을 수 있음


  • 속성이 고정되지 않고 어떤 값이라도 넣을 수 있다.
  • index는 초기값을 할당하지 않아도 된다.
// class => object
// {mark: 'male', jade: 'male'}
// {chloe: 'female', alex: 'male', anna: female}

class Students {
 [index: string]: "male" | "female"; //타입 대신 정확한 값을 넣을 수 있음
}

const a = new Students();
a.mark = 'male';
a.jade = 'male';

console.log(a); // Students { mark: 'male', jade: 'male' }

const b = new Students();
b.chloe = 'female';
b.alex = 'male';
b.anna = 'female';

console.log(b); // Students { chloe: 'female', alex: 'male', anna: 'female' }

 

 

 


static properties & methods

들어오는 데이터에 상관없이 공통적으로 쓸 수 있는 곳에는 static를 사용하여 메모리의 사용을 줄일 수 있다.


class Person {
  public static city = "Seoul";
  public static change() {
    Person.city = "Jeju";
  }
}

const p1 = new Person();
p1.hello(); // static을 붙이면 메서드로 인식하지 않음

Person.hello(); //클래스.함수()
Person.city;

 

  • class Personnew오브젝트를 만들지 않아도, 클래스로부터 만들어진 객체에서 공통적으로 사용하고 싶은 데이터(속성이나 메서드)에 static을 붙이면 공유 가능
  • private을 사용해도 내부에서 클래스.함수( )형식으로 사용 가능
  • 정적으로 공유되면 값이 변경됨

 

 


Singletons 🤦‍♀️

private과 static으로 알아보는 싱글톤 패턴


앱이 실행되는 중간에 오브젝트로부터 하나의 클래스(instance)만 생성해 사용하는 디자인 패턴이다.

동일한 instance를 반복해서 제공하는 정적 메서드를 만든다.

 

class ClassName {
	private static instance: ClassName | null = null;
	public static getInstance(): ClassName {
    	// ClassName으로부터 만든 object가 없으면 리턴
        if (ClassName.instace === null) {
        	ClassName.instace = new ClassName();
        }
        
        return ClassNAme.instace;
    }
    
	private constructor() {}
}

const a = ClassName.getInstance();
const b = ClassName.getInstance();

console.log(a === b); // true

 

 

 

 


Inheritance 상속📌


(예제 1)

다양한 도형을 만들 때 class로 정의하려면 어떻게 해야할까?

높이, 너비, 색채 등을 지정할 수 있을 텐데 이들이 반복되어지는 속성! shape을 한 번에 정의하여 재사용할 수 있다.

class Shape {
	constructor(width, height, color) {
    	this.width = width;
        this.height = height;
        this. color = color;
    }
    
    draw() {
    	console.log(`drawing ${this.color} color!`);
    }
    
    getArea() {
    	return this.width * this.height;
    }
}

class Rectangle extends Sahpe {}
class Triangle extends Sahpe { // override
	draw() {
    	super.draw(); // override는 덮어씌어지는데 부모그대로 상속받으려면 super
        console.log('⚠');
    }
	getArea() {
    	return (this.width * this.height) / 2; 
    }
}

const rectangle = new Rectangle(20, 20, 'blue');
rectangle.draw(); // drawing blue color!
console.log(rectangle.getArea()); // 400
console.log(Triangle.getArea()); // 200

 

(예제2)

class Parent {
	constructor(protected _name: string, private _age: number) {} // protected 상속관계에서만 접근

	public print(): void {
    	console.log(`이름은 ${this._name}이고 나이는 #{this._age}`);
    }
    
    protected printName(): void {
    	console.log(this._name, this._age);
    }
}

const p = new Parent("Siot", 99);
p.print();


class Child extends Parent {
	public gender = "male"; // public으로 override(덮어씌우기) 가능
    
    constructor(age: number) {
    	super("Siot", age); // 생성자 override, 부모 생성자 호출하는 키워드 super는 항상 먼저 작성
        this.printName();
    }
}

const c = new Child(20);
c.print(); 

// Siot, 20
// 이름은 Siot이고 나이는 20

 

 

 


Abstract classes 🤦‍♀️


완전하지 않은 클래스를 표현 , 완전하지 않은 클래스는 new로 개체를 표현할 수 없다. 상속과 같은 기능으로 완전하게 만든 후 사용

abstract class AbstractPerson {
	protected _name: string = "Siot";
    
    abstract setName(name: string): void;
}

// new AbstractPerson()

class Person extends AbstractPerson {
	setName(name: string): void {
    	this._name = name;
    }
}

const p = new Person();
p.setName();

 

 

🌍이웅재님, 유튜버 엘리님 강의요약

728x90
728x90

 

 


🚨 Interfaces

◽ javascript에서는 interfaces개념이 없다. 컴파일 되어도 js파일에 드러나지 않는다.

interfaces는 타입을 만들어내는 방식 중 하나로 외부적으로 드러나는 개체의 사용 방식이 적힌 타입

◽ 개체의 각 요소들의 타입을 편리하게 설정할 수 있다.


💻 interface1.ts

interface Person1 { 
  name: string;
  age: number; 
}

function hello1(person: Person1): void {
  console.log(`안녕 ${person.name}이야`)
}

const p1: Person1 = {
  name: 'Siot',
  age: 99
}

hello1(p1);

💻 컴파일 후 interface1.js

"use strict";
function hello1(person) {
    console.log(`안녕 ${person.name}이야`);
}
const p1 = {
    name: 'Siot',
    age: 99
};
hello1(p1);

 

 

 


optional property


물음표 ?

◽ 상황에 따라 필요할 때마다 선택적으로 사용

interface Person2 { 
  name: string;
  age?: number; 
}

function hello2(person: Person2): void {
  console.log(`안녕 ${person.name}이야.`);
}

hello2({ name: 'siot' });

age?: number; : 있어도 없어도 되는 속성에는 ?를 붙인다

 

 

indexable types

◽ 인덱서의 타입은 string, number만 지정 가능

◽ (index의 타입을 string으로 하면) 어떤 것이든 []안에 프로퍼티 이름으로 지정 가능

interface Person3 {
  name: string;
  age?: number;
  [index: string]: any;
}

function hello3(person: Person3): void {
  console.log(`안녕 ${person.name}이야.`);
}

const p31: Person3 = {
  name: 'Siot',
  age: 99
};

const p32: Person3 = {
  name: 'Kim',
  sisters: ['siot', 'ieung']
};

const p33: Person3 = {
  name: 'Lee',
  father: p31,
  mother: p32, 
}

hello3(p33)

 

 


function in interface

interface안에서 function정의하기


interface Person4 {
  name: string;
  age: number;
  hello(): void; //매개변수가 없는 hello함수의 리턴 타입void
}

 

💻 위 코드에서 interface Person4 내에 함수가 정의되는 방법

1️⃣ hello프로퍼티에 function함수를 할당할 수 있다. 또는

const p41: Person4 = {
  name: 'siot',
  age: 99,
  hello: function(): void {
    console.log(`안녕 ${this.name}이야.`);
  }
};

2️⃣ function 키워드 없이 hello함수 할당

const p42: Person4 = {
  name: 'siot',
  age: 99,
  hello(): void {
    console.log(`안녕 ${this.name}이야.`);
  }
};

3️⃣ 화살표함수

const p43: Person4 = {
  name: 'siot',
  age: 99,
  hello: (): void => {
    console.log(`안녕 ${this.name}이야.`); 
  }
};
// 화살표함수는 this를 사용할 수 없으므로 이 파일은 컴파일되지 않는다.

◽ 단, 화살표함수는 this를 사용할 수 없다.

 

💻 node를 이용해 함수 실행 결과

p41.hello();
p42.hello();

 

 


class implements interface

 ◽ interface를 이용해서 class만들기

 ◽ 외부로는 interface만 노출하고 내부적으로는 class구현을 하는 방식으로 객체 지향에서 많이 사용되는 방법이다.


💻 interface Iperson1 지정 후 class Person implements Iperson1까지만 작성하면 VSCode에서 자동으로 작성법 도움을 받을 수 있다. 에러가 발생하는 단어를 클릭 시 💡파란색전구 아이콘이 뜨는데 이거를 클릭하면 Iperson1변수의 인터페이스를 그대로 구현할 수 있다.

interface IPerson1 {
  name: string;
  age?: number;
  hello(): void;
}

class Person implements IPerson1 {}

💻 Iperson1을 구현하여 class Person으로 가져오기

(이때 name에 초기값을 지정해주지 않아 error가 발생하므로)

interface IPerson1 {
  name: string;
  age?: number;
  hello(): void;
}

class Person implements IPerson1 {
  name: string;
  age?: number | undefined;
  hello(): void {
    throw new Error("Method not implemented.");
  }
}

constructor생성자 함수를 만들어 name속성을 인수로 가져와 할당한다.

interface IPerson1 {
  name: string;
  age?: number;
  hello(): void;
}

class Person implements IPerson1 {
  name: string;
  age?: number | undefined;

  constructor(name: string) {
    this.name = name; 
  }

  hello(): void {
   console.log(`안녕! ${this.name}이야.`);
  }
  
}

 

💻 함수 실행

interface IPerson1 을 만족하는 class Person을 만들어서 type처럼 사용 가능하다. class이름으로 사용 가능하지만 interface이름으로 불러오는 게 정확한 표현이다. 

const person: IPerson1 = new Person("siot"); // constructor(name: string)
person.hello();

 

 


interface extends interface

 ◽ interface를 상속받아 interface만들기


💻 interface IKorean extends IPerson2 : IPerson2를 상속받는 IKoreanIPerson2의 내용을 모두 가질 수 있다.

interface IPerson2 {
  name: string;
  age?: number;
}

interface IKorean extends IPerson2 {
  city: string;
}

const k: IKorean = {
  name: 'siot',
  city: 'korea',
  age: 99,
}

 

 


function interface

 ◽ 함수에 대해 interface를 만드는 방법, 함수를 타이핑하는 방법


interface HelloPerson {
  (name: string, age?: number): void;
}

const helloPerson: HelloPerson = function(name: string) {
  console.log(`안녕! ${name}이야.`);
}

💻 function인수에 interface와 일치하지 않는 값을 넣었을 때 오류 예시

  ◽ interface HelloPerson의 optional property인 age?function인수에는 age:number로 할당할 때 일치하지 않은 에러임을 발생시킨다.

  ◽ 변수 helloPerson의 타입은 interface HelloPerson과만 관계를 맺으므로 function인수의 타입이 맞지 않을 때 오류가 날 수 있음을 이해하는 것이 중요

 

 


Readonly Interface Properties

 ◽ 함수에 대해 interface를 만드는 방법, 함수를 타이핑하는 방법


💻 속성 앞에 readonly붙여주기

interface Person8 {
  name: string;
  age?: number;
  readonly gender: string;
}

const p81: Person8 = {
  name: 'siot',
  gender: 'female',
}

p81.gender = "male";

 ◽ readonly는 새로운 값을 넣을 수 없다.

 ◽ interface를 만들 때 한 번 작성 후 바뀌지 않는 값 앞에는 readonly를 붙여주는 습관이 중요하다.

 ◽ interfacereadonly를 쓰면 class에서도 그대로 받아 쓰기 때문에 유용하다. 

readonly 속성 gender에 다른 값을 넣으려 할 때 error발생

 

 

 


🤷‍♀️ type alias VS interface

 ◽ 타입을 부르는 이름 VS 새로운 타입을 만들어내는 것

 ◽ 타입 별칭과 인터페이스 표기법의 차이점


💻 function 

// type alias
type EatType = (food: string) => void;

// interface
interface IEat {
  (food: string): void;
}

💻 array 

// type alias
type PersonList = string[];

// interface
interface IPersonList {
  [index: number]: string; // indexable types
}

💻 intersection

interface ErrorHandling {
  success: boolean;
  error?: { message: string };
}

interface ArtistsData {
  artists: { name: string }[];
}

// type alias
type ArtistsResponseType = ArtistsData & ErrorHandling;

// interface
interface IArtistsResponse extends ArtistsData, ErrorHandling {} // 다중 상속

let art: ArtistsResponseType;
let iar: IArtistsResponse;

💻 union types

interface Bird {
  fly(): void;
  layEggs(): void;
}

interface Fish {
  swim(): void;
  layEggs(): void;
}

type PetType = Bird | Fish;

interface IPet extends PetType {} // error TS2312: An interface can only extend an object type or intersection of object types with statically known members.

class Pet implements PetType {} // error TS2422: A class can only implement an object type or intersection of object types with statically known members.

💻 Declaration Merging - interface

 ◽ type alias에서는 불가능한 기능

 ◽ interface 이름이 같을 때 합쳐짐

 ◽ htmlelements를 확장할 때 기존에 있는 interface에 추가하여 합칠 때, interface를 한번 더 선언하여 삽입하면 자동으로 합쳐져서 굳이 기존 내용을 작성할 필요가 없다.

interface MergingInterface {
  a: string;
}

interface MergingInterface {
  b: string;
}

let mi: MergingInterface;
mi.

 

728x90
728x90


typeRoots, types


  ◽ 타이핑이 안 되어 있는 자바스크립트 라이브러리를 사용할 때 타입을 지정해주는 옵션

  ◽ 이전에는 타입스크립트가 아닌 서드파티에서 제공해주고 있었음 -> typescript 2.0이상 지원

  ◽ typeRoots와 types 를 같이 사용하지 않는다.

  ◽ 보이는 모든 @types패키지가 컴파일에 포함된다.

 

👩‍💻 React 예제

import React form "react";

Could not find a declaration file for module 'react'.

-> 리액트 모듈의 선언 파일을 찾을 수 없으므로 해결법을 제시한다.

-> 타입 정의 : npm i --save-dev @types/react 

타입이 지정되지 않은 react 라이브러리 오류

  ◽ 경로 : node_modules > @types > react > index.d.ts

    ◾ index.d.ts가 react의 type definition으로 적용된다. (default)

 

✅ typeRoots

  ◽ ./node_modules/@types처럼 작동하는 폴더를 특정함

  ◽ 잘 쓰이지 않는 모듈은 직접 폴더를 만들어 지정해줄 수 있는 장점이 있다.

  ◽ "typeRoots"를 지정하면 배열 안에 들어있는 경로들의 패키지만 가져온다. ./node_modules/@types의 패키지는 포함되지 않는다.

 

 types

  ◽ react와 같이 타입 패키지 네임으로 지정함

{
  "compilerOptions": {
    "types" : ["node", "lodash", "express"]
  }
}

  ◽ typescript 2.0 부터 사용 가능해진 내장 type definition 시스템

  ◽ 아무런 설정하지 않으면 node_modules/@types라는 모든 경로를 찾아서 사용

  ◽ 배열 안의 모듈 혹은 ./node_modules/@types/ 안의 모듈 이름에서 찾아온다.

  ◽ "types": [] 빈 배열을 넣는다는건 이 시스템을 이용하지 않겠다는 것 

 

 


target, lib


✅ target

  ◽ 타입스크립트가 어떤 런타임 환경에서 실행할 수 있는지 결정하는 요소

  ◽ 빌드의 결과물을 어떤 버전으로 할 것이냐에 관한 설정

  ◽ JavaScript 언어 버전을 설정하고 호환되는 라이브러리 선언을 포함하여 컴파일링 할 때 적용됨

{
  "target": {
    "type": "string",
    "default": "ES3",
    "anyOf": [
      {
        "enum": [
          "ES3",
          "ES5",
          "ES6",
          "ES2015",
          "ES2016",
          "ES2017",
          "ES2018",
          "ES2019",
          "ES2020",
          "ESNext" // 최신 ES 제안 기능을 대상으로 함
        ]
      }
  }
}

 

✅ lib

  ◽ 최종적으로 실행하고자 하는 환경에 맞게 기본 타입을 정의

  ◽ console과 같이 기본으로 번들된 라이브러리 선언 파일 세트를 지정함

  ◽ lib를 지정하지 않을 때,

    ◾ target es3이면 디폴트로 lib.d.ts를 사용

    ◾ target es5이면, 디폴트로 dom, es5, scripthost를 사용

    ◾ target es6이면, 디폴트로 dom, es6, dom.iterable, scripthost를 사용

  ◽ lib를 지정하면 그 lib배열로만 라이브러리를 사용한다.

​    ◾ 빈[] => 'no definition found 00'

 

 


outDir, outFile, rootDir


✅ outFile

  ◽ 번들러 형태로 지원, 일반적인 형태로는 하나의 파일로 만들수 없다

  ◽ 모듈이 시스템 혹은 amd와 같은 형태로 지원되어야 파일을 하나로 만들수 있음

  ◽ commonjs나 es6 모듈 형식으로 모듈을 합해 하나의 파일로 만드는 역할을 하지 않음

  ◽ 시스템 js나 amd 를 이용해 사용할 때 하나의 파일로 만들어짐

 

✅ rootDir

  ◽ 소스폴더를 그대로 가져가 outDir 컴파일 가능

 

✅ outDir

  ◽ 컴파일하고자 하는 영역을 대상으로 outDir로 지정된 특정 폴더의 계층에 맞춰 생성

  ◽ 컴파일된 결과물을 모아놓는 폴더 이름을 dist로 만들었을 때 outDir로 폴더를 지정하면 편하게 사용

  ◽ 사용하지 않으면 files, include, exclude에 의해서 최상위 영역을 잡고 그대로 컴파일된 결과물에 계층을 맞추게 된다.

 

👩‍💻 예시

  ◽ rootDir를 지정하면 최상위폴더에서 컴파일되어 outDir를 만들어 파일을 이동한다.

​    ◾ "src폴더"를 지정하면 프로젝트 폴더에서 "dist폴더"를 만든다.

 

 1️⃣ src폴더에 test.ts파일 생성

 2️⃣ tsconfig.json에서 옵션 지정

      "outDir": "./dist", "rootDir": "./src" 

 3️⃣ test.ts파일이 outDir(dist폴더)와 함께 생성됨

  ◽ rootDir가 지정되지 않았을 때는 최상위폴더에서 컴파일되어 outDir를 만들고 그 내부에 폴더째(src폴더) 만든다.

 

 


strict

엄격하게 타입을 확인하는 옵션 활성화


 --nolmplicitAny

  ◽ 명시적이지 않게 any 타입을 사용하여 표현식과 선언에 사용하면 에러 발생

  ◽ 타입스크립트가 추론을 실패한 경우 any가 맞다면 any라고 지정해야 한다.

 

✅ suppressImplicitAnyIndexErrors

  ◽ nolmplicitAny를 사용할 때 인덱스 객체에 인덱스 시그니처가 없는 경우 오류가 발생하는 것을 예외 처리

  ◽ obj['foo']로 사용할 때 인덱스 객체라 판단, 타입에 인덱스 시그니처가 없는 경우 에러 발생

  -> suppressImplicitAnyindexErrors옵션은 이런 경우 발생하는 에러를 예외 처리

 

✅ --nolmplicitThis

  ◽ 명시적이지 않게 any타입을 사용하여 this 표현식에 사용하면 에러 발생

  ◽ 첫 번째 매개변수에 this가 올 때, this에 타입을 명시하지 않으면 nolmplicitAny가 에러 발생

  ◽ javascript에서 this는 예약어이기 때문에 매개변수에 넣으면 SyntaxError 발생

  ◽ call, apply, bind와 같이 this를 대체하여 함수 콜을 하는 용도로 쓰임 -> thisany로 명시적으로 지정하는 것은 합리적 

  ◽ class에서는 this를 사용하면서 nolmplicitThis관련 에러가 발생하지 않는다.

  ◽ class에서 constructor를 제외한 멤버 함수의 첫번째 매개변수도 일반함수와 마찬가지로 this를 사용할 수 있다.

 

✅ --strictNullChecks

  ◽ strickNullChecks를 적용하면

​    ◾ 모든 타입은 null, undefined값을 가질 수 없고 가지려면 union type으로 직접 명시해야 한다.

​    ◾ 단, anynull, undefined할당 가능하며 void에는 undefined할당 가능

​    ◾ 함수를 선언할 때부터 매개변수와 리턴 값에 정확한 타입을 지정할 수 있다.

  ◽ strickNullChecks를 적용하지 않을 경우 

​    ◾ 모든 타입은 null, undefined값을 할당 가능

 

✅ --strictFunctionTypes

  ◽ 함수 타입에 대한 이변량(bivariant) 매개변수 검사를 비활성화한다.

    (Animal -> Greyhound) <: (Dog -> Dog)

  ◽ 반환 타입은 공변적(covariant)고 인자 타입은 반공변적(contravariant)지만 typescript에서 인자 타입은 공변적이면서 반공변적인 게 문제다.

​    ◾ 이를 해결하기 위한 옵션으로 strickFunctionTypes를 활성화해서 에러를 발생하게 한다.

const button = document.querySelector('#id') as HTMLButtonElement;
button.addEventListener('keydown', (e: MouseEvent) => {});

  ◽ 위와 같은 코드도 에러를 발생시키지 않앗으나 옵션을 활성화하면 에러가 발생하게 된다.

 

✅ --strictPropertyInitialization

  ◽ 정의되지 않은 클래스의 속성이 생성자에서 초기화되었는지 확인

  ◽ 이 옵션을 사용하려면 strcitNullChecks를 사용하도록 설정해야 한다. 

  ◽ 선언되어 있지만 실제로 초기 값을 할당하지 않아 에러 발생

  ◽ constructor에서 초기 값을 할당한 경우 -> 정상

  ◽ constructor에서 안 하는 경우

​    ◾ 다른 함수(async함수, 비동기적으로 할당)로 initialization하면 constructor에는 async를 사용할 수 없다.

​    ◾ 어디선가 할당될 것이므로 에러를 무시하라는 의미로 !느낌표

 

✅ --strictBindCallApply

  ◽ function의 내장 함수인 bind, call, apply를 사용할 때 더욱 엄격하게 검사하는 옵션

  ◽ bind: 해당 함수 안에서 사용할 this와 인자를 설정

  ◽ call, apply: this와 인자를 설정한 후 실행

​    ◾ call: 함수의 인자를 여러 인자의 배열로 넣어 사용

​    ◾ apply: 모든 인자를 하나의 배열에 넣어 사용

 

✅ --alwaysStrict

  ◽ 각 소스 파일에 대해 javascript의 strict mode로 코드를 분석하고 "엄격하게 사용함"을 내보낸다.

  ◽ syntex에러가 ts error로 나온다. 

  ◽ 컴파일된 javascript파일에 "use strict" 추가됨 

728x90
728x90

🌍 Typescript deep dive

typescript용어들이 한국어로 매우 잘 번역되어 있다.

 

Introduction - TypeScript Deep Dive

JavsScript, TypeScript, React 등 영어 고유 명사는 원문 유지, 필요시 한(영) 병서

radlohead.gitbook.io

 

 

 


💻 Compilation context


  ◽ 그룹화된 타입스크립트 파일을 자바스크립트로 변환할 때의 설정

  ◽ 컴파일 할 파일, 컴파일 하지 않을 파일 선택

  ◽ 사용할 타입스크립트 컴파일 옵션 지정

  ◽ 옵션들은 tsconfig.json파일에 선언되어 있다. 원하는 옵션을 주석처리하거나 type을 지정할 수 있다.

 

 


💻 tsconfig top level properties

tsconfig의 최상위 속성

 

compileOnSave


  ◽ 저장과 동시에 컴파일하는 기능

  ◽ default는 false다.

"type": "boolean"

 

extends


  ◽ 설정을 상속받아 사용하기

  ◽ 설정을 상속 받아올 부모 설정의 경로를 작성한다.

  ◽ typescript 2.1 이상

"extends" : "./base.json"
"type" : "string"

 

📍 typescript에서 공개한 extends할 수 있는 설정을 모아놓은 repository

 

 

GitHub - tsconfig/bases: Hosts TSConfigs to extend in a TypeScript app, tuned to a particular runtime environment

Hosts TSConfigs to extend in a TypeScript app, tuned to a particular runtime environment - GitHub - tsconfig/bases: Hosts TSConfigs to extend in a TypeScript app, tuned to a particular runtime envi...

github.com

npm install --save-dev @tsconfig/deno

{
    "extends": "@tsconfig/deno/tsconfig.json".
}

 

files, include, exclude


  ◽ 서로 관계지어 발생되지만 "files"옵션이 최우선순위로, "exclude"에 설정되어 있어도 "files"옵션을 우선으로 한다.

  ◽ "include""exclude"속성은 glob과 유사한 파일 패턴 목록을 갖는다.

 

✅ files

  ◽ 프로젝트 내 어떤 파일을 컴파일할 것인지 결정하는 옵션

  ◽ 설정하지 않으면 기본적으로 모든 파일을 컴파일한다.

  ◽ 상대 혹은 절대 경로의 리스트 배열로 지정한다.

{
    "comilerOptions": { 
        "noImplicitAny": "commonjs"
    },
    "files": [
        "core.ts",
        "sys.ts",
        "types.ts",
        "scanner.ts",
        "parser.ts",
        "utilities.ts",
        "binder.ts",
        "checker.ts",
        "emitter.ts",
        "program.ts",
        "commandLineParser.ts",
        "tsc.ts",
        "diagnosticInformationMap.generated.ts"
    ]
}

✅ exclude

  ◽ "files""include"모두 지정되어 있지 않다면 "exclude"로 제외된 것을 제외하고 모든 TypeScript파일을 포함하는 디렉토리와 하위 디렉토리에 포함시킨다.

  ◽ "include"에 있는 파일을 제외시키는데 영향을 주지만, "files"에는 영향을 주지 않는다.

  ◽ "exclude" 속성이 지정되지 않으면, "Outdir"컴파일러 옵션을 사용하여 지정된 디렉토리의 파일은 항상 제외한다."include"에 포함되어도 항상 제외함

  ◽ "exclude"속성에 디렉토리가 지정되어 있지 않으면, 기본적으로 node_modules, bower_componets, jspm_packages, outDir를 제외한다.

  ◽ typsescript 2.0 이상

✅ include

  ◽ glob pattern에 일치하는 파일들을 컴파일에 포함

  ◽ typsescript 2.0 이상

✅ glob 와일드카드

  ◽ 와일드카드 문자로 여러 파일 이름의 집합을 지정할 수 있다.

    ◾ * 0개 이상의 문자와 매칭

    ◾ ? 한 문자와 매칭

    ◾ **/ 반복적으로 모든 하위 디렉토리와 매칭

  ◽ 기본적으로 .ts .tsx .d .ts 확장자 파일은 포함이며 allowJs가 true로 설정되어 있을 때만 .js .jsx가 포함된다.

 

728x90
728x90

맥OS의 기본 쉘이 bash1에서 zsh로 바뀌면서 nvm설치가 순조롭게 되지 않는다. 

zsh: command not found: nvm은 nvm명령어를 사용할 수 없다는 의미로 nvm을 설치하기 위해 약간의 설정이 필요하다.

기본 shell이 다르기 때문에 환경 변수를 달리해줘야 하는 것이다. 

*쉘은 운영체제에서 사용자가 입력하는 명령어를 리드, 해석, 실행하는 인터페이스 프로그램이다. OS에 따라서 쉘은 달라질 수 있다.

 

 

1. homebrew설치

맥OS용 패키지 관리 앱

/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"

환경변수 추가

$ vi ~/.zshrc

zshrc파일 내 경로 삽입

ㄴ i를 누르면 insert상태로 변경 -> 코드 작성 후 -> ESC

$ export "PATH=/opt/homebrew/bin:$PATH"

 

저장후 종료 명령어

$ :wq!

 

터미널 재실행 혹은 zshrc파일 실행

$ source ~/.zshrc

 

 

 

 

2. zsh: command not found: nvm

zshrc파일 생성

$ touch ~/.zshrc

 

zshrc파일 실행

$ vi ~/.zshrc

환경변수 추가

export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # This loads nvm

숨김 파일까지 전부 표시 : ls -a

파일 삭제 명령어 : rm

 

 

3. Gem::FilePermissionError 

brew로 rbenv설치 후 rbenv로 관리되는 ruby를 설치하는 과정

*gem은 오픈소스 기능 모듈로 ruby 앱이나 라이브러리를 설치, 패키지 관리

$ brew update
$ brew install rbenv ruby-build

버전확인

$ rbenv versions

설치할 수 있는 ruby 버전 확인

$ rbenv install -l

원하는 버전으로 설치

$ rbenv install 버전번호

버전확인

$ rbenv versions

환경변수 추가

$ vim ~/.zshrc
[[ -d ~/.rbenv  ]] && \
  export PATH=${HOME}/.rbenv/bin:${PATH} && \
  eval "$(rbenv init -)"
$ source ~/.zshrc

 

 

4. gem으로 jekyll, bundler 설치하기

4-1. bundler 설치

$ gem install bundler
$ gem install jekyll bundler

 

Jekyll 버전확인

$ jekyll -v

4-2. 로컬로 repository 다운 -> 다운받은 스킨파일을 복붙한 뒤 commit

4-3. 로컬에서 사이트보기

$ bundle exec jekyll serve

http://localhost:4000/

 

728x90
+ Recent posts
728x90