Skip to content

Latest commit

ย 

History

History
454 lines (337 loc) ยท 22.3 KB

typescript-3.8.md

File metadata and controls

454 lines (337 loc) ยท 22.3 KB

ํƒ€์ž…-์ „์šฉ Imports ์™€ Exports (Type-Only Imports and Exports)

์ด ๊ธฐ๋Šฅ์€ ๋Œ€๋ถ€๋ถ„์˜ ์‚ฌ์šฉ์ž์—๊ฒ ์ƒ๊ฐํ•  ํ•„์š”๊ฐ€ ์—†์„ ์ˆ˜๋„ ์žˆ์ง€๋งŒ; --isolatedModules, TypeScript์˜ transpileModule API, ๋˜๋Š” Babel์—์„œ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•˜๋ฉด ์ด ๊ธฐ๋Šฅ๊ณผ ๊ด€๋ จ์ด ์žˆ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

TypeScript 3.8์€ ํƒ€์ž…-์ „์šฉ imports, exports๋ฅผ ์œ„ํ•œ ์ƒˆ๋กœ์šด ๊ตฌ๋ฌธ์ด ์ถ”๊ฐ€๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

import type { SomeThing } from "./some-module.js";

export type { SomeThing };

import type์€ ํƒ€์ž… ํ‘œ๊ธฐ์™€ ์„ ์–ธ์— ์‚ฌ์šฉ๋  ์„ ์–ธ๋งŒ import ํ•ฉ๋‹ˆ๋‹ค. ์ด๋Š” ํ•ญ์ƒ ์™„์ „ํžˆ ์ œ๊ฑฐ๋˜๋ฏ€๋กœ, ๋Ÿฐํƒ€์ž„์— ๋‚จ์•„์žˆ๋Š” ๊ฒƒ์€ ์—†์Šต๋‹ˆ๋‹ค. ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ, export type์€ ํƒ€์ž… ๋ฌธ๋งฅ์— ์‚ฌ์šฉํ•  export๋งŒ ์ œ๊ณตํ•˜๋ฉฐ, ์ด ๋˜ํ•œ TypeScript์˜ ์ถœ๋ ฅ๋ฌผ์—์„œ ์ œ๊ฑฐ๋ฉ๋‹ˆ๋‹ค.

ํด๋ž˜์Šค๋Š” ๋Ÿฐํƒ€์ž„์— ๊ฐ’์„ ๊ฐ€์ง€๊ณ  ์žˆ๊ณ  ๋””์ž์ธ-ํƒ€์ž„์— ํƒ€์ž…์ด ์žˆ์œผ๋ฉฐ ์‚ฌ์šฉ์€ ์ƒํ™ฉ์—-๋”ฐ๋ผ ๋‹ค๋ฅด๋‹ค๋Š” ๊ฒƒ์„ ์œ ์˜ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ํด๋ž˜์Šค๋ฅผ import ํ•˜๊ธฐ ์œ„ํ•ด import type์„ ์‚ฌ์šฉํ•˜๋ฉด, ํ™•์žฅ ๊ฐ™์€ ๊ฒƒ์€ ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

import type { Component } from "react";

interface ButtonProps {
    // ...
}

class Button extends Component<ButtonProps> {
    //               ~~~~~~~~~
    // error! 'Component' only refers to a type, but is being used as a value here.

    // ...
}

์ด์ „์— Flow๋ฅผ ์‚ฌ์šฉํ•ด๋ณธ ์ ์ด ์žˆ๋‹ค๋ฉด, ์ด ๊ตฌ๋ฌธ์€ ์ƒ๋‹นํžˆ ์œ ์‚ฌํ•ฉ๋‹ˆ๋‹ค. ํ•œ ๊ฐ€์ง€ ์ฐจ์ด์ ์€ ์ฝ”๋“œ๊ฐ€ ๋ชจํ˜ธํ•ด ๋ณด์ด์ง€ ์•Š๋„๋ก ๋ช‡ ๊ฐ€์ง€ ์ œํ•œ์„ ๋‘์—ˆ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

// 'Foo'๋งŒ ํƒ€์ž…์ธ๊ฐ€? ํ˜น์€ ๋ชจ๋“  import ์„ ์–ธ์ด ํƒ€์ž…์ธ๊ฐ€?
// ์ด๋Š” ๋ช…ํ™•ํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ์˜ค๋ฅ˜๋กœ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค.

import type Foo, { Bar, Baz } from "some-module";
//     ~~~~~~~~~~~~~~~~~~~~~~
// error! A type-only import can specify a default import or named bindings, but not both.

import type๊ณผ ํ•จ๊ป˜, TypeScript 3.8์€ ๋Ÿฐํƒ€์ž„ ์‹œ ์‚ฌ์šฉ๋˜์ง€ ์•Š๋Š” import์—์„œ ๋ฐœ์ƒํ•˜๋Š” ์ž‘์—…์„ ์ œ์–ดํ•˜๊ธฐ ์œ„ํ•ด ์ƒˆ๋กœ์šด ์ปดํŒŒ์ผ๋Ÿฌ ํ”Œ๋ž˜๊ทธ๋ฅผ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค: importsNotUsedAsValues. ์ด ํ”Œ๋ž˜๊ทธ๋Š” 3 ๊ฐ€์ง€ ๋‹ค๋ฅธ ๊ฐ’์„ ๊ฐ€์ง‘๋‹ˆ๋‹ค:

  • remove: ์ด๋Š” imports๋ฅผ ์ œ๊ฑฐํ•˜๋Š” ํ˜„์žฌ ๋™์ž‘์ด๋ฉฐ, ๊ณ„์† ๊ธฐ๋ณธ๊ฐ’์œผ๋กœ ์ž‘๋™ํ•  ๊ฒƒ์ด๋ฉฐ, ๊ธฐ์กด ๋™์ž‘์„ ๋ฐ”๊พธ๋Š” ๋ณ€ํ™”๊ฐ€ ์•„๋‹™๋‹ˆ๋‹ค.
  • preserve: ์ด๋Š” ์‚ฌ์šฉ๋˜์ง€ ์•Š๋Š” ๊ฐ’๋“ค์„ ๋ชจ๋‘ ๋ณด์กดํ•ฉ๋‹ˆ๋‹ค. ์ด๋กœ ์ธํ•ด imports/side-effects๊ฐ€ ๋ณด์กด๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • error: ์ด๋Š” ๋ชจ๋“  (preserve option ์ฒ˜๋Ÿผ) ๋ชจ๋“  imports๋ฅผ ๋ณด์กดํ•˜์ง€๋งŒ, import ๊ฐ’์ด ํƒ€์ž…์œผ๋กœ๋งŒ ์‚ฌ์šฉ๋  ๊ฒฝ์šฐ ์˜ค๋ฅ˜๋ฅผ ๋ฐœ์ƒ์‹œํ‚ต๋‹ˆ๋‹ค. ์ด๋Š” ์‹ค์ˆ˜๋กœ ๊ฐ’์„ importํ•˜์ง€ ์•Š์ง€๋งŒ ์‚ฌ์ด๋“œ ์ดํŒฉํŠธ import๋ฅผ ๋ช…์‹œ์ ์œผ๋กœ ๋งŒ๋“ค๊ณ  ์‹ถ์„ ๋•Œ ์œ ์šฉํ•ฉ๋‹ˆ๋‹ค.

์ด ๊ธฐ๋Šฅ์— ๋Œ€ํ•œ ๋” ์ž์„ธํ•œ ์ •๋ณด๋Š”, import type์„ ์–ธ์ด ์‚ฌ์šฉ๋ ์ˆ˜ ์žˆ๋Š” ๋ฒ”์œ„๋ฅผ ํ™•๋Œ€ํ•˜๋Š” pull request, ์™€ ๊ด€๋ จ๋œ ๋ณ€๊ฒฝ ์‚ฌํ•ญ์—์„œ ์ฐพ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

ECMAScript ๋น„๊ณต๊ฐœ ํ•„๋“œ (ECMAScript Private Fields)

TypeScript 3.8 ์€ ECMAScript์˜ stage-3 ํด๋ž˜์Šค ํ•„๋“œ ์ œ์•ˆ์˜ ๋น„๊ณต๊ฐœ ํ•„๋“œ๋ฅผ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค.

class Person {
    #name: string

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

    greet() {
        console.log(`Hello, my name is ${this.#name}!`);
    }
}

let jeremy = new Person("Jeremy Bearimy");

jeremy.#name
//     ~~~~~
// ํ”„๋กœํผํ‹ฐ '#name'์€ 'Person' ํด๋ž˜์Šค ์™ธ๋ถ€์—์„œ ์ ‘๊ทผํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.
// ์ด๋Š” ๋น„๊ณต๊ฐœ ์‹๋ณ„์ž๋ฅผ ๊ฐ€์ง€๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

์ผ๋ฐ˜์ ์ธ ํ”„๋กœํผํ‹ฐ๋“ค(private ์ง€์ •์ž๋กœ ์„ ์–ธํ•œ ๊ฒƒ๋„)๊ณผ ๋‹ฌ๋ฆฌ, ๋น„๊ณต๊ฐœ ํ•„๋“œ๋Š” ๋ช‡ ๊ฐ€์ง€ ๋ช…์‹ฌํ•ด์•ผ ํ•  ๊ทœ์น™์ด ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ์ค‘ ๋ช‡๋ช‡์€:

  • ๋น„๊ณต๊ฐœ ํ•„๋“œ๋Š” # ๋ฌธ์ž๋กœ ์‹œ์ž‘ํ•ฉ๋‹ˆ๋‹ค. ๋•Œ๋•Œ๋กœ ์ด๋ฅผ ๋น„๊ณต๊ฐœ ์ด๋ฆ„(private names) ์ด๋ผ๊ณ  ๋ถ€๋ฆ…๋‹ˆ๋‹ค.
  • ๋ชจ๋“  ๋น„๊ณต๊ฐœ ํ•„๋“œ ์ด๋ฆ„์€ ์ด๋ฅผ ํฌํ•จํ•œ ํด๋ž˜์Šค ๋ฒ”์œ„์—์„œ ์œ ์ผํ•ฉ๋‹ˆ๋‹ค.
  • public ๋˜๋Š” private ๊ฐ™์€ TypeScript ์ ‘๊ทผ ์ง€์ •์ž๋Š” ๋น„๊ณต๊ฐœ ํ•„๋“œ๋กœ ์‚ฌ์šฉ๋  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.
  • JS ์‚ฌ์šฉ์ž๋กœ๋ถ€ํ„ฐ๋„ ๋น„๊ณต๊ฐœ ํ•„๋“œ๋Š” ์ด๋ฅผ ํฌํ•จํ•œ ํด๋ž˜์Šค ๋ฐ–์—์„œ ์ ‘๊ทผํ•˜๊ฑฐ๋‚˜ ํƒ์ง€ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค! ๋•Œ๋•Œ๋กœ ์ด๋ฅผ ๊ฐ•ํ•œ ๋น„๊ณต๊ฐœ(hard privacy) ๋ผ๊ณ  ๋ถ€๋ฆ…๋‹ˆ๋‹ค.

"๊ฐ•ํ•œ" ๋น„๊ณต๊ฐœ์™€ ๋ณ„๋„๋กœ, ๋น„๊ณต๊ฐœ ํ•„๋“œ์˜ ๋˜ ๋‹ค๋ฅธ ์žฅ์ ์€ ์œ ์ผํ•˜๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, ์ผ๋ฐ˜์ ์ธ ํ”„๋กœํผํ‹ฐ ์„ ์–ธ์€ ํ•˜์œ„ํด๋ž˜์Šค์—์„œ ๋ฎ์–ด์“ฐ๊ธฐ ์‰ฝ์Šต๋‹ˆ๋‹ค.

class C {
    foo = 10;

    cHelper() {
        return this.foo;
    }
}

class D extends C {
    foo = 20;

    dHelper() {
        return this.foo;
    }
}

let instance = new D();
// 'this.foo' ๋Š” ๊ฐ ์ธ์Šคํ„ด์Šค๋งˆ๋‹ค ๊ฐ™์€ ํ”„๋กœํผํ‹ฐ๋ฅผ ์ฐธ์กฐํ•ฉ๋‹ˆ๋‹ค.
console.log(instance.cHelper()); // '20' ์ถœ๋ ฅ
console.log(instance.dHelper()); // '20' ์ถœ๋ ฅ

๋น„๊ณต๊ฐœ ํ•„๋“œ์—์„œ๋Š”, ํฌํ•จํ•˜๊ณ  ์žˆ๋Š” ํด๋ž˜์Šค์—์„œ ๊ฐ๊ฐ์˜ ํ•„๋“œ ์ด๋ฆ„์ด ์œ ์ผํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ด์— ๋Œ€ํ•ด ๊ฑฑ์ •ํ•˜์ง€ ์•Š์•„๋„ ๋ฉ๋‹ˆ๋‹ค.

class C {
    #foo = 10;

    cHelper() {
        return this.#foo;
    }
}

class D extends C {
    #foo = 20;

    dHelper() {
        return this.#foo;
    }
}

let instance = new D();
// 'this.#foo' ๋Š” ๊ฐ ํด๋ž˜์Šค์•ˆ์˜ ๋‹ค๋ฅธ ํ•„๋“œ๋ฅผ ์ฐธ์กฐํ•ฉ๋‹ˆ๋‹ค.
console.log(instance.cHelper()); // '10' ์ถœ๋ ฅ
console.log(instance.dHelper()); // '20' ์ถœ๋ ฅ

์•Œ์•„ ๋‘๋ฉด ์ข‹์€ ๋˜ ๋‹ค๋ฅธ ์ ์€ ๋‹ค๋ฅธ ํƒ€์ž…์œผ๋กœ ๋น„๊ณต๊ฐœ ํ•„๋“œ์— ์ ‘๊ทผํ•˜๋ฉด TypeError ๋ฅผ ๋ฐœ์ƒํ•œ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

class Square {
    #sideLength: number;

    constructor(sideLength: number) {
        this.#sideLength = sideLength;
    }

    equals(other: any) {
        return this.#sideLength === other.#sideLength;
    }
}

const a = new Square(100);
const b = { sideLength: 100 };

// Boom!
// TypeError: attempted to get private field on non-instance
// ์ด๋Š” `b` ๊ฐ€ `Square`์˜ ์ธ์Šคํ„ด์Šค๊ฐ€ ์•„๋‹ˆ๊ธฐ ๋•Œ๋ฌธ์— ์‹คํŒจ ํ•ฉ๋‹ˆ๋‹ค.
console.log(a.equals(b));

๋งˆ์ž๋ง‰์œผ๋กœ, ๋ชจ๋“  ์ผ๋ฐ˜ .js ํŒŒ์ผ ์‚ฌ์šฉ์ž๋“ค์˜ ๊ฒฝ์šฐ, ๋น„๊ณต๊ฐœ ํ•„๋“œ๋Š” ํ•ญ์ƒ ํ• ๋‹น๋˜๊ธฐ ์ „์— ์„ ์–ธ๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

class C {
    // '#foo' ์„ ์–ธ์ด ์—†์Šต๋‹ˆ๋‹ค.
    // :(

    constructor(foo: number) {
        // SyntaxError!
        // '#foo'๋Š” ์“ฐ์—ฌ์ง€๊ธฐ ์ „์— ์„ ์–ธ๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
        this.#foo = foo;
    }
}

JavaScript๋Š” ํ•ญ์ƒ ์‚ฌ์šฉ์ž๋“ค์—๊ฒŒ ์„ ์–ธ๋˜์ง€ ์•Š์€ ํ”„๋กœํผํ‹ฐ์— ์ ‘๊ทผ์„ ํ—ˆ์šฉํ–ˆ์ง€๋งŒ, TypeScript๋Š” ํ•ญ์ƒ ํด๋ž˜์Šค ํ”„๋กœํผํ‹ฐ ์„ ์–ธ์„ ์š”๊ตฌํ–ˆ์Šต๋‹ˆ๋‹ค. ๋น„๊ณต๊ฐœ ํ•„๋“œ๋Š”, .js ๋˜๋Š” .ts ํŒŒ์ผ์—์„œ ๋™์ž‘ํ•˜๋Š”์ง€ ์ƒ๊ด€์—†์ด ํ•ญ์ƒ ์„ ์–ธ์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.

class C {
    /** @type {number} */
    #foo;

    constructor(foo: number) {
        // ๋™์ž‘ํ•ฉ๋‹ˆ๋‹ค.
        this.#foo = foo;
    }
}

๊ตฌํ˜„์— ๋Œ€ํ•œ ๋” ๋งŽ์€ ์ •๋ณด๋Š”, the original pull request๋ฅผ ์ฐธ๊ณ ํ•˜์„ธ์š”

์–ด๋–ค ๊ฒƒ์„ ์‚ฌ์šฉํ•ด์•ผ ํ• ๊นŒ์š”? (Which should I use?)

์ด๋ฏธ TypeScript ์œ ์ €๋กœ์„œ ์–ด๋–ค ์ข…๋ฅ˜์˜ ๋น„๊ณต๊ฐœ๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•˜๋Š”์ง€์— ๋Œ€ํ•œ ๋งŽ์€ ์งˆ๋ฌธ์„ ๋ฐ›์•˜์Šต๋‹ˆ๋‹ค: ์ฃผ๋กœ, "private ํ‚ค์›Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•˜๋‚˜์š” ์•„๋‹ˆ๋ฉด ECMAScript์˜ ํ•ด์‹œ/์šฐ๋ฌผ (#) ๋น„๊ณต๊ฐœ ํ•„๋“œ๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•˜๋‚˜์š”?" ์ƒํ™ฉ๋งˆ๋‹ค ๋‹ค๋ฆ…๋‹ˆ๋‹ค!

ํ”„๋กœํผํ‹ฐ์—์„œ, TypeScript์˜ private ์ง€์ •์ž๋Š” ์™„์ „ํžˆ ์ง€์›Œ์ง‘๋‹ˆ๋‹ค - ์ด๋Š” ๋Ÿฐํƒ€์ž„์—์„œ๋Š” ์™„์ „ํžˆ ์ผ๋ฐ˜ ํ”„๋กœํผํ‹ฐ์ฒ˜๋Ÿผ ๋™์ž‘ํ•˜๋ฉฐ ์ด๊ฒƒ์ด private ์ง€์ •์ž๋กœ ์„ ์–ธ๋˜์—ˆ๋‹ค๊ณ  ์•Œ๋ฆด ๋ฐฉ๋ฒ•์ด ์—†์Šต๋‹ˆ๋‹ค. private ํ‚ค์›Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ, ๋น„๊ณต๊ฐœ๋Š” ์˜ค์ง ์ปดํŒŒ์ผ-ํƒ€์ž„/๋””์ž์ธ-ํƒ€์ž„์—๋งŒ ์‹œํ–‰๋˜๋ฉฐ, JavaScript ์‚ฌ์šฉ์ž์—๊ฒŒ๋Š” ์ „์ ์œผ๋กœ ์˜๋„-๊ธฐ๋ฐ˜์ž…๋‹ˆ๋‹ค.

class C {
    private foo = 10;
}

// ์ด๋Š” ์ปดํŒŒ์ผ ํƒ€์ž„์— ์˜ค๋ฅ˜์ด์ง€๋งŒ
// TypeScript ๊ฐ€ .js ํŒŒ์ผ๋กœ ์ถœ๋ ฅํ–ˆ์„ ๋•Œ๋Š”
// ์ž˜ ๋™์ž‘ํ•˜๋ฉฐ '10'์„ ์ถœ๋ ฅํ•ฉ๋‹ˆ๋‹ค.
console.log(new C().foo);    // '10' ์ถœ๋ ฅ
//                  ~~~
// error! Property 'foo' is private and only accessible within class 'C'.

// TypeScript ์˜ค๋ฅ˜๋ฅผ ํ”ผํ•˜๊ธฐ ์œ„ํ•œ "ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•" ์œผ๋กœ
// ์บ„ํŒŒ์ผ ํƒ€์ž„์— ์ด๊ฒƒ์„ ํ—ˆ์šฉํ•ฉ๋‹ˆ๋‹ค.
console.log(new C()["foo"]); // prints '10'

์ด ๊ฐ™์€ ์ข…๋ฅ˜์˜ "์•ฝํ•œ ๋น„๊ณต๊ฐœ(soft privacy)"๋Š” ์‚ฌ์šฉ์ž๊ฐ€ API์— ์ ‘๊ทผํ•  ์ˆ˜ ์—†๋Š” ์ƒํƒœ์—์„œ ์ผ์‹œ์ ์œผ๋กœ ์ž‘์—…์„ ํ•˜๋Š” ๋ฐ ๋„์›€์ด ๋˜๋ฉฐ, ์–ด๋–ค ๋Ÿฐํƒ€์ž„์—์„œ๋„ ๋™์ž‘ํ•ฉ๋‹ˆ๋‹ค.

๋ฐ˜๋ฉด์—, ECMAScript์˜ # ๋น„๊ณต๊ฐœ๋Š” ์™„๋ฒฝํ•˜๊ฒŒ ํด๋ž˜์Šค ๋ฐ–์—์„œ ์ ‘๊ทผ ๋ถˆ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.

class C {
    #foo = 10;
}

console.log(new C().#foo); // SyntaxError
//                  ~~~~
// TypeScript ๋Š” ์˜ค๋ฅ˜๋ฅผ ๋ณด๊ณ  ํ•˜๋ฉฐ *๋˜ํ•œ*
// ๋Ÿฐํƒ€์ž„์—๋„ ๋™์ž‘ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

console.log(new C()["#foo"]); // undefined ์ถœ๋ ฅ
//          ~~~~~~~~~~~~~~~
// TypeScript ๋Š” 'noImplicitAny' ํ•˜์—์„œ ์˜ค๋ฅ˜๋ฅผ ๋ณด๊ณ ํ•˜๋ฉฐ
// `undefined`๋ฅผ ์ถœ๋ ฅํ•ฉ๋‹ˆ๋‹ค.

์ด๋Ÿฐ ๊ฐ•ํ•œ ๋น„๊ณต๊ฐœ(hard privacy)๋Š” ์•„๋ฌด๋„ ๋‚ด๋ถ€๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๋„๋ก ์—„๊ฒฉํ•˜๊ฒŒ ๋ณด์žฅํ•˜๋Š”๋ฐ ์œ ์šฉํ•ฉ๋‹ˆ๋‹ค. ๋งŒ์•ฝ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์ž‘์„ฑ์ž์ผ ๊ฒฝ์šฐ, ๋น„๊ณต๊ฐœ ํ•„๋“œ๋ฅผ ์ œ๊ฑฐํ•˜๊ฑฐ๋‚˜ ์ด๋ฆ„์„ ๋ฐ”๊พธ๋Š” ๊ฒƒ์ด ๊ธ‰๊ฒฉํ•œ ๋ณ€ํ™”๋ฅผ ์ดˆ๋ž˜์„œ๋Š” ์•ˆ๋ฉ๋‹ˆ๋‹ค.

์–ธ๊ธ‰ํ–ˆ๋“ฏ์ด, ๋‹ค๋ฅธ ์žฅ์ ์€ ECMAScript์˜ # ๋น„๊ณต๊ฐœ๊ฐ€ ์ง„์งœ ๋น„๊ณต๊ฐœ์ด๊ธฐ ๋•Œ๋ฌธ์— ์„œ๋ธŒํด๋ž˜์‹ฑ์„ ์‰ฝ๊ฒŒ ํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ECMAScript # ๋น„๊ณต๊ฐœ ํ•„๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด, ์–ด๋–ค ์„œ๋ธŒ ํด๋ž˜์Šค๋„ ํ•„๋“œ ๋„ค์ด๋ฐ ์ถฉ๋Œ์— ๋Œ€ํ•ด ๊ฑฑ์ •ํ•  ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. TypeScript์˜ privateํ”„๋กœํผํ‹ฐ ์„ ์–ธ์—์„œ๋Š”, ์‚ฌ์šฉ์ž๋Š” ์—ฌ์ „ํžˆ ์ƒ์œ„ ํด๋ž˜์Šค์— ์„ ์–ธ๋œ ํ”„๋กœํผํ‹ฐ๋ฅผ ์ง“๋ฐŸ์ง€ ์•Š๋„๋ก ์ฃผ์˜ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

ํ•œ ๊ฐ€์ง€ ๋” ์ƒ๊ฐํ•ด๋ด์•ผ ํ•  ๊ฒƒ์€ ์ฝ”๋“œ๊ฐ€ ์‹คํ–‰๋˜๊ธฐ๋ฅผ ์˜๋„ํ•˜๋Š” ๊ณณ์ž…๋‹ˆ๋‹ค. ํ˜„์žฌ TypeScript๋Š” ์ด ๊ธฐ๋Šฅ์„ ECMAScript 2015 (ES6) ์ด์ƒ ๋ฒ„์ „์„ ๋Œ€์ƒ์œผ๋กœ ํ•˜์ง€ ์•Š์œผ๋ฉด ์ง€์›ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ์ด๋Š” ํ•˜์œ„ ๋ ˆ๋ฒจ ๊ตฌํ˜„์ด ๋น„๊ณต๊ฐœ๋ฅผ ๊ฐ•์ œํ•˜๊ธฐ ์œ„ํ•ด WeakMap์„ ์‚ฌ์šฉํ•˜๋Š”๋ฐ, WeakMap์€ ๋ฉ”๋ชจ๋ฆฌ ๋ˆ„์ˆ˜๋ฅผ ์žƒ์œผํ‚ค์ง€ ์•Š๋„๋ก ํด๋ฆฌํ•„๋  ์ˆ˜ ์—†๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ๋ฐ˜๋ฉด, TypeScript์˜ private-์„ ์–ธ ํ”„๋กœํผํ‹ฐ๋Š” ๋ชจ๋“  ๋Œ€์ƒ์—์„œ ๋™์ž‘ํ•ฉ๋‹ˆ๋‹ค- ECMAScript3์—์„œ๋„!

๋งˆ์ง€๋ง‰ ๊ณ ๋ ค ์‚ฌํ•ญ์€ ์†๋„ ์ผ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค: private ํ”„๋กœํผํ‹ฐ๋Š” ๋‹ค๋ฅธ ์–ด๋–ค ํ”„๋กœํผํ‹ฐ์™€ ๋‹ค๋ฅด์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์—, ์–ด๋–ค ๋Ÿฐํƒ€์ž„์„ ๋Œ€์ƒ์œผ๋กœ ํ•˜๋‹จ ๋‹ค๋ฅธ ํ”„๋กœํผํ‹ฐ์™€ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ์ ‘๊ทผ ์†๋„๊ฐ€ ๋น ๋ฅผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋ฐ˜๋ฉด์—, # ๋น„๊ณต๊ฐœ ํ•„๋“œ๋Š” WeakMap์„ ์ด์šฉํ•ด ๋‹ค์šด ๋ ˆ๋ฒจ ๋˜๊ธฐ ๋•Œ๋ฌธ์— ์‚ฌ์šฉ ์†๋„๊ฐ€ ๋Š๋ ค์งˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์–ด๋–ค ๋Ÿฐํƒ€์ž„์€ # ๋น„๊ณต๊ฐœ ํ•„๋“œ ๊ตฌํ˜„์„ ์ตœ์ ํ™” ํ•˜๊ณ , ๋” ๋น ๋ฅธ WeakMap์„ ๊ตฌํ˜„ํ•˜๊ณ  ์‹ถ์„ ์ˆ˜ ์žˆ์ง€๋งŒ, ๋ชจ๋“  ๋Ÿฐํƒ€์ž„์—์„œ ๊ทธ๋ ‡์ง€ ์•Š์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

export * as ns ๊ตฌ๋ฌธ (export * as ns Syntax)

๋‹ค๋ฅธ ๋ชจ๋“ˆ์˜ ๋ชจ๋“  ๋ฉค๋ฒ„๋ฅผ ํ•˜๋‚˜์˜ ๋ฉค๋ฒ„๋กœ ๋‚ด๋ณด๋‚ด๋Š” ๋‹จ์ผ ์ง„์ž…์ ์„ ๊ฐ–๋Š” ๊ฒƒ์€ ์ข…์ข… ์ผ๋ฐ˜์ ์ž…๋‹ˆ๋‹ค.

import * as utilities from "./utilities.js";
export { utilities };

์ด๋Š” ๋งค์šฐ ์ผ๋ฐ˜์ ์ด์–ด์„œ ECMAScript2020์€ ์ตœ๊ทผ์— ์ด ํŒจํ„ด์„ ์ง€์›ํ•˜๊ธฐ ์œ„ํ•ด์„œ ์ƒˆ๋กœ์šด ๊ตฌ๋ฌธ์„ ์ถ”๊ฐ€ํ–ˆ์Šต๋‹ˆ๋‹ค.

export * as utilities from "./utilities.js";

์ด๊ฒƒ์€ JavaScript์— ๋Œ€ํ•œ ํ›Œ๋ฅญํ•œ ์‚ถ์˜ ์งˆ์˜ ํ–ฅ์ƒ์ด๋ฉฐ, TypeScript 3.8์€ ์ด ๊ตฌ๋ฌธ์„ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค. ๋ชจ๋“ˆ ๋Œ€์ƒ์ด es2020 ์ด์ „์ธ ๊ฒฝ์šฐ, TypeScript๋Š” ์ฒซ ๋ฒˆ์งธ ์ค„์˜ ์ฝ”๋“œ ์Šค๋‹ˆํŽซ์„ ๋”ฐ๋ผ์„œ ๋ฌด์–ธ๊ฐ€๋ฅผ ์ถœ๋ ฅํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์ตœ์ƒ์œ„-๋ ˆ๋ฒจ await (Top-Level await)

TypeScript 3.8์€ "์ตœ์ƒ์œ„-๋ ˆ๋ฒจ await"์ด๋ผ๋Š” ํŽธ๋ฆฌํ•œ ECMAScript ๊ธฐ๋Šฅ์„ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค.

JavaScript ์‚ฌ์šฉ์ž๋Š” await์„ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด async ํ•จ์ˆ˜๋ฅผ ๋„์ž…ํ•˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ๋งŽ์œผ๋ฉฐ, ์ด๋ฅผ ์ •์˜ํ•œ ํ›„ ์ฆ‰์‹œ ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค.

async function main() {
    const response = await fetch("...");
    const greeting = await response.text();
    console.log(greeting);
}

main()
    .catch(e => console.error(e))

์ด์ „์˜ JavaScript(์œ ์‚ฌํ•œ ๊ธฐ๋Šฅ์„ ๊ฐ€์ง„ ๋Œ€๋ถ€๋ถ„์˜ ๋‹ค๋ฅธ ์–ธ์–ด๋“ค๊ณผ ํ•จ๊ป˜)์—์„œ await์€ async ํ•จ์ˆ˜ ๋‚ด์—์„œ ๋งŒ ํ—ˆ์šฉ๋˜์—ˆ๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ์ตœ์ƒ์œ„-๋ ˆ๋ฒจ await๋กœ, ์šฐ๋ฆฌ๋Š” ๋ชจ๋“ˆ์˜ ์ตœ์ƒ์œ„ ๋ ˆ๋ฒจ์—์„œ await์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

const response = await fetch("...");
const greeting = await response.text();
console.log(greeting);

// ๋ชจ๋“ˆ์ธ์ง€ ํ™•์ธ
export {};

์œ ์˜ํ•  ์ ์ด ์žˆ์Šต๋‹ˆ๋‹ค: ์ตœ์ƒ์œ„-๋ ˆ๋ฒจ await์€ module์˜ ์ตœ์ƒ์œ„ ๋ ˆ๋ฒจ์—์„œ๋งŒ ๋™์ž‘ํ•˜๋ฉฐ, ํŒŒ์ผ์€ TypeScript๊ฐ€ import๋‚˜ export๋ฅผ ์ฐพ์„ ๋•Œ์—๋งŒ ๋ชจ๋“ˆ๋กœ ๊ฐ„์ฃผ๋ฉ๋‹ˆ๋‹ค. ์ผ๋ถ€ ๊ธฐ๋ณธ์ ์ธ ๊ฒฝ์šฐ์— export {}์™€ ๊ฐ™์€ ๋ณด์ผ๋Ÿฌ ํ”Œ๋ ˆ์ดํŠธ๋ฅผ ์ž‘์„ฑํ•˜์—ฌ ์ด๋ฅผ ํ™•์ธํ•  ํ•„์š”๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

์ด๋Ÿฌํ•œ ๊ฒฝ์šฐ๊ฐ€ ์˜ˆ์ƒ๋˜๋Š” ๋ชจ๋“  ํ™˜๊ฒฝ์—์„œ ์ตœ์ƒ์œ„ ๋ ˆ๋ฒจ await์€ ๋™์ž‘ํ•˜์ง€ ์•Š์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํ˜„์žฌ, target ์ปดํŒŒ์ผ๋Ÿฌ ์˜ต์…˜์ด es2017 ์ด์ƒ์ด๊ณ , module์ด esnext ๋˜๋Š” system์ธ ๊ฒฝ์šฐ์—๋งŒ ์ตœ์ƒ์œ„ ๋ ˆ๋ฒจ await์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋ช‡๋ช‡ ํ™˜๊ฒฝ๊ณผ ๋ฒˆ๋“ค๋Ÿฌ๋‚ด์—์„œ์˜ ์ง€์›์€ ์ œํ•œ์ ์œผ๋กœ ์ž‘๋™ํ•˜๊ฑฐ๋‚˜ ์‹คํ—˜์  ์ง€์›์„ ํ™œ์„ฑํ™”ํ•ด์•ผ ํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ตฌํ˜„์— ๊ด€ํ•œ ๋” ์ž์„ธํ•œ ์ •๋ณด๋Š” the original pull request์„ ํ™•์ธํ•˜์„ธ์š”.

es2020์šฉ target๊ณผ module (es2020 for target and module)

TypeScript 3.8์€ es2020์„ module๊ณผ target ์˜ต์…˜์œผ๋กœ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ์„ ํƒ์  ์ฒด์ด๋‹ (optional chaining), nullish ๋ณ‘ํ•ฉ (nullish coalescing), export * as ns ๊ทธ๋ฆฌ๊ณ  ๋™์ ์ธ import(...) ๊ตฌ๋ฌธ๊ณผ ๊ฐ™์€ ECMAScript 2020 ๊ธฐ๋Šฅ์ด ์œ ์ง€๋ฉ๋‹ˆ๋‹ค. ๋˜ํ•œ bigint ๋ฆฌํ„ฐ๋Ÿด์ด esnext ์•„๋ž˜์— ์•ˆ์ •์ ์ธ target์„ ๊ฐ–๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค.

JSDoc ํ”„๋กœํผํ‹ฐ ์ง€์ •์ž (JSDoc Property Modifiers)

TypeScript 3.8๋Š” allowJs ํ”Œ๋ž˜๊ทธ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ JavaScript ํŒŒ์ผ์„ ์ง€์›ํ•˜๊ณ  checkJs ์˜ต์…˜์ด๋‚˜ // @ts-check ์ฃผ์„์„ .js ํŒŒ์ผ ๋งจ ์œ„์— ์ถ”๊ฐ€ํ•˜์—ฌ JavaScript ํŒŒ์ผ์˜ ํƒ€์ž…-๊ฒ€์‚ฌ๋ฅผ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค.

JavaScript ํŒŒ์ผ์—๋Š” ํƒ€์ž…-๊ฒ€์‚ฌ๋ฅผ ์œ„ํ•œ ์ „์šฉ ๊ตฌ๋ฌธ์ด ์—†๊ธฐ ๋•Œ๋ฌธ์— TypeScript๋Š” JSDoc์„ ํ™œ์šฉํ•ฉ๋‹ˆ๋‹ค. TypeScript 3.8์€ ํ”„๋กœํผํ‹ฐ์— ๋Œ€ํ•œ ๋ช‡ ๊ฐ€์ง€ ์ƒˆ๋กœ์šด JSDoc ํƒœ๊ทธ๋ฅผ ์ธ์‹ํ•ฉ๋‹ˆ๋‹ค.

๋จผ์ € ์ ‘๊ทผ ์ง€์ •์ž์ž…๋‹ˆ๋‹ค: @public, @private ๊ทธ๋ฆฌ๊ณ  @protected์ž…๋‹ˆ๋‹ค. ์ด ํƒœ๊ทธ๋“ค์€ TypeScript ๋‚ด์—์„œ ๊ฐ๊ฐ public, private, protected์™€ ๋™์ผํ•˜๊ฒŒ ๋™์ž‘ํ•ฉ๋‹ˆ๋‹ค.

// @ts-check

class Foo {
    constructor() {
        /** @private */
        this.stuff = 100;
    }

    printStuff() {
        console.log(this.stuff);
    }
}

new Foo().stuff;
//        ~~~~~
// ์˜ค๋ฅ˜! 'stuff' ํ”„๋กœํผํ‹ฐ๋Š” private ์ด๊ธฐ ๋•Œ๋ฌธ์— ์˜ค์ง 'Foo' ํด๋ž˜์Šค ๋‚ด์—์„œ๋งŒ ์ ‘๊ทผ์ด ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.
  • @public์€ ํ•ญ์ƒ ์•”์‹œ์ ์ด๋ฉฐ ์ƒ๋žต๋  ์ˆ˜ ์žˆ์ง€๋งŒ, ์–ด๋””์„œ๋“  ํ•ด๋‹น ํ”„๋กœํผํ‹ฐ์— ์ ‘๊ทผ ๊ฐ€๋Šฅ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค.
  • @private์€ ์˜ค์ง ํ”„๋กœํผํ‹ฐ๋ฅผ ํฌํ•จํ•˜๋Š” ํด๋ž˜์Šค ๋‚ด์—์„œ ํ•ด๋‹น ํ”„๋กœํผํ‹ฐ ์‚ฌ์šฉ ๊ฐ€๋Šฅ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค.
  • @protected๋Š” ํ”„๋กœํผํ‹ฐ๋ฅผ ํฌํ•จํ•˜๋Š” ํด๋ž˜์Šค์™€ ํŒŒ์ƒ๋œ ๋ชจ๋“  ํ•˜์œ„ ํด๋ž˜์Šค๋‚ด์—์„œ ํ•ด๋‹น ํ”„๋กœํผํ‹ฐ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์ง€๋งŒ, ํฌํ•จํ•˜๋Š” ํด๋ž˜์Šค์˜ ์ธ์Šคํ„ด์Šค๋Š” ํ•ด๋‹น ํ”„๋กœํผํ‹ฐ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

๋‹ค์Œ์œผ๋กœ @readonly ์ง€์ •์ž๋ฅผ ์ถ”๊ฐ€ํ•˜์—ฌ ํ”„๋กœํผํ‹ฐ๊ฐ€ ์ดˆ๊ธฐํ™” ๊ณผ์ • ๋‚ด์—์„œ๋งŒ ๊ฐ’์ด ์“ฐ์ด๋Š” ๊ฒƒ์„ ๋ณด์žฅํ•ฉ๋‹ˆ๋‹ค.

// @ts-check

class Foo {
    constructor() {
        /** @readonly */
        this.stuff = 100;
    }

    writeToStuff() {
        this.stuff = 200;
        //   ~~~~~
        // 'stuff'๋Š” ์ฝ๊ธฐ-์ „์šฉ(read-only) ํ”„๋กœํผํ‹ฐ์ด๊ธฐ ๋•Œ๋ฌธ์— ํ• ๋‹นํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.
    }
}

new Foo().stuff++;
//        ~~~~~
// 'stuff'๋Š” ์ฝ๊ธฐ-์ „์šฉ(read-only) ํ”„๋กœํผํ‹ฐ์ด๊ธฐ ๋•Œ๋ฌธ์— ํ• ๋‹นํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

๋ฆฌ๋ˆ…์Šค์—์„œ ๋” ๋‚˜์€ ๋””๋ ‰ํ„ฐ๋ฆฌ ๊ฐ์‹œ์™€ watchOptions

TypeScript 3.8์—์„œ๋Š” node_modules์˜ ๋ณ€๊ฒฝ์‚ฌํ•ญ์„ ํšจ์œจ์ ์œผ๋กœ ์ˆ˜์ง‘ํ•˜๋Š”๋ฐ ์ค‘์š”ํ•œ ์ƒˆ๋กœ์šด ๋””๋ ‰ํ„ฐ๋ฆฌ ๊ฐ์‹œ ์ „๋žต์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

๋ฆฌ๋ˆ…์Šค์™€ ๊ฐ™์€ ์šด์˜์ฒด์ œ์—์„œ TypeScript๋Š” node_modules์— ๋””๋ ‰ํ„ฐ๋ฆฌ ์™“์ณ(ํŒŒ์ผ ์™“์ณ์™€๋Š” ๋ฐ˜๋Œ€๋กœ)๋ฅผ ์„ค์น˜ํ•˜๊ณ , ์˜์กด์„ฑ ๋ณ€ํ™”๋ฅผ ๊ฐ์ง€ํ•˜๊ธฐ ์œ„ํ•ด ๋งŽ์€ ํ•˜์œ„ ๋””๋ ‰ํ„ฐ๋ฆฌ๋ฅผ ์„ค์น˜ํ•ฉ๋‹ˆ๋‹ค. ์™œ๋ƒํ•˜๋ฉด ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ํŒŒ์ผ ์™“์ณ์˜ ์ˆ˜๋Š” ์ข…์ข… node_modules์˜ ํŒŒ์ผ ์ˆ˜์— ์˜ํ•ด ๊ฐ€๋ ค์ง€๊ธฐ ๋•Œ๋ฌธ์ด๊ณ , ์ถ”์ ํ•  ๋””๋ ‰ํ„ฐ๋ฆฌ ์ˆ˜๊ฐ€ ์ ๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

TypeScript์˜ ์ด์ „ ๋ฒ„์ „์€ ํด๋”์— ๋””๋ ‰ํ„ฐ๋ฆฌ ์™“์ณ๋ฅผ ์ฆ‰์‹œ ์„ค์น˜ํ•˜๋ฉฐ, ์ดˆ๊ธฐ์—๋Š” ๊ดœ์ฐฎ์„ ๊ฒ๋‹ˆ๋‹ค; ํ•˜์ง€๋งŒ, npm install ํ•  ๋•Œ, node_modules์•ˆ์—์„œ ๋งŽ์€ ์ผ๋“ค์ด ๋ฐœ์ƒํ•  ๊ฒƒ์ด๊ณ , TypeScript๋ฅผ ์••๋„ํ•˜์—ฌ, ์ข…์ข… ์—๋””ํ„ฐ ์„ธ์…˜์„ ์•„์ฃผ ๋Š๋ฆฌ๊ฒŒ ๋งŒ๋“ญ๋‹ˆ๋‹ค. ์ด๋ฅผ ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•ด, TypeScript 3.8์€ ๋””๋ ‰ํ„ฐ๋ฆฌ ์™“์ณ๋ฅผ ์„ค์น˜ํ•˜๊ธฐ ์ „์— ์กฐ๊ธˆ ๊ธฐ๋‹ค๋ ค์„œ ๋ณ€๋™์„ฑ์ด ๋†’์€ ๋””๋ ‰ํ„ฐ๋ฆฌ์—๊ฒŒ ์•ˆ์ •๋  ์ˆ˜ ์žˆ๋Š” ์‹œ๊ฐ„์„ ์ค๋‹ˆ๋‹ค.

์™œ๋ƒํ•˜๋ฉด ๋ชจ๋“  ํ”„๋กœ์ ํŠธ๋Š” ๋‹ค๋ฅธ ์ „๋žต์—์„œ ๋” ์ž˜ ์ž‘๋™ํ•  ์ˆ˜ ์žˆ๊ณ , ์ด ์ƒˆ๋กœ์šด ๋ฐฉ๋ฒ•์€ ๋‹น์‹ ์˜ ์ž‘์—… ํ๋ฆ„์—์„œ๋Š” ์ž˜ ๋งž์ง€ ์•Š์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. TypeScript 3.8์€ ํŒŒ์ผ๊ณผ ๋””๋ ‰ํ„ฐ๋ฆฌ๋ฅผ ๊ฐ์‹œํ•˜๋Š”๋ฐ ์–ด๋–ค ๊ฐ์‹œ ์ „๋žต์„ ์‚ฌ์šฉํ• ์ง€ ์ปดํŒŒ์ผ๋Ÿฌ/์–ธ์–ด ์„œ๋น„์Šค์— ์•Œ๋ ค์ค„ ์ˆ˜ ์žˆ๋„๋ก tsconfig.json๊ณผ jsconfig.json์— watchOptions๋ž€ ์ƒˆ๋กœ์šด ํ•„๋“œ๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

{
    // ์ผ๋ฐ˜์ ์ธ ์ปดํŒŒ์ผ๋Ÿฌ ์˜ต์…˜๋“ค
    "compilerOptions": {
        "target": "es2020",
        "moduleResolution": "node",
        // ...
    },

    // NEW: ํŒŒ์ผ/๋””๋ ‰ํ„ฐ๋ฆฌ ๊ฐ์‹œ๋ฅผ ์œ„ํ•œ ์˜ต์…˜
    "watchOptions": {
        // ํŒŒ์ผ๊ณผ ๋””๋ ‰ํ„ฐ๋ฆฌ์— ๋„ค์ดํ‹ฐ๋ธŒ ํŒŒ์ผ ์‹œ์Šคํ…œ ์ด๋ฒคํŠธ ์‚ฌ์šฉ
        "watchFile": "useFsEvents",
        "watchDirectory": "useFsEvents",

        // ์—…๋ฐ์ดํŠธ๊ฐ€ ๋นˆ๋ฒˆํ•  ๋•Œ
        // ์—…๋ฐ์ดํŠธํ•˜๊ธฐ ์œ„ํ•ด ๋” ์ž์ฃผ ํŒŒ์ผ์„ ํด๋ง
        "fallbackPolling": "dynamicPriority"
    }
}

watchOptions๋Š” ๊ตฌ์„ฑํ•  ์ˆ˜ ์žˆ๋Š” 4๊ฐ€์ง€ ์ƒˆ๋กœ์šด ์˜ต์…˜์ด ํฌํ•จ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.

  • watchFile: ๊ฐ ํŒŒ์ผ์˜ ๊ฐ์‹œ ๋ฐฉ๋ฒ• ์ „๋žต. ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์„ค์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:
    • fixedPollingInterval: ๊ณ ์ •๋œ ๊ฐ„๊ฒฉ์œผ๋กœ ๋ชจ๋“  ํŒŒ์ผ์˜ ๋ณ€๊ฒฝ์„ 1์ดˆ์— ์—ฌ๋Ÿฌ ๋ฒˆ ๊ฒ€์‚ฌํ•ฉ๋‹ˆ๋‹ค.
    • priorityPollingInterval: ๋ชจ๋“  ํŒŒ์ผ์˜ ๋ณ€๊ฒฝ์„ 1์ดˆ์— ์—ฌ๋Ÿฌ ๋ฒˆ ๊ฒ€์‚ฌํ•ฉ๋‹ˆ๋‹ค, ํ•˜์ง€๋งŒ ํœด๋ฆฌ์Šคํ‹ฑ์„ ์‚ฌ์šฉํ•˜์—ฌ ํŠน์ • ํƒ€์ž…์˜ ํŒŒ์ผ์€ ๋‹ค๋ฅธ ํƒ€์ž…์˜ ํŒŒ์ผ๋ณด๋‹ค ๋œ ์ž์ฃผ ๊ฒ€์‚ฌํ•ฉ๋‹ˆ๋‹ค.
    • dynamicPriorityPolling: ๋™์  ํ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋œ-์ž์ฃผ ์ˆ˜์ •๋œ ํŒŒ์ผ์€ ์ ๊ฒŒ ๊ฒ€์‚ฌํ•ฉ๋‹ˆ๋‹ค.
    • useFsEvents (๋””ํดํŠธ): ํŒŒ์ผ ๋ณ€ํ™”์— ์šด์˜์ฒด์ œ/ํŒŒ์ผ ์‹œ์Šคํ…œ์˜ ๋„ค์ดํ‹ฐ๋ธŒ ์ด๋ฒคํŠธ๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.
    • useFsEventsOnParentDirectory: ํŒŒ์ผ์„ ํฌํ•จํ•˜๊ณ  ์žˆ๋Š” ๋””๋ ‰ํ„ฐ๋ฆฌ ๋ณ€๊ฒฝ์„ ๊ฐ์ง€ํ•  ๋•Œ, ์šด์˜์ฒด์ œ/ํŒŒ์ผ ์‹œ์Šคํ…œ์˜ ๋„ค์ดํ‹ฐ๋ธŒ ์ด๋ฒคํŠธ๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ํŒŒ์ผ ์™“์ณ๋ฅผ ์ ๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์ง€๋งŒ, ๋œ ์ •ํ™•ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • watchDirectory: ์žฌ๊ท€์ ์ธ ํŒŒ์ผ-๊ฐ์‹œ ๊ธฐ๋Šฅ์ด ์—†๋Š” ์‹œ์Šคํ…œ ์•ˆ์—์„œ ์ „์ฒด ๋””๋ ‰ํ„ฐ๋ฆฌ ํŠธ๋ฆฌ๊ฐ€ ๊ฐ์‹œ๋˜๋Š” ์ „๋žต. ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์„ค์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:
    • fixedPollingInterval: ๊ณ ์ •๋œ ๊ฐ„๊ฒฉ์œผ๋กœ ๋ชจ๋“  ๋””๋ ‰ํ„ฐ๋ฆฌ์˜ ๋ณ€๊ฒฝ์„ 1์ดˆ์— ์—ฌ๋Ÿฌ ๋ฒˆ ๊ฒ€์‚ฌํ•ฉ๋‹ˆ๋‹ค.
    • dynamicPriorityPolling: ๋™์  ํ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋œ-์ž์ฃผ ์ˆ˜์ •๋œ ๋””๋ ‰ํ„ฐ๋ฆฌ๋Š” ์ ๊ฒŒ ๊ฒ€์‚ฌํ•ฉ๋‹ˆ๋‹ค.
    • useFsEvents (๋””ํดํŠธ): ๋””๋ ‰ํ„ฐ๋ฆฌ ๋ณ€๊ฒฝ์— ์šด์˜์ฒด์ œ/ํŒŒ์ผ ์‹œ์Šคํ…œ์˜ ๋„ค์ดํ‹ฐ๋ธŒ ์ด๋ฒคํŠธ๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.
  • fallbackPolling: ํŒŒ์ผ ์‹œ์Šคํ…œ ์ด๋ฒคํŠธ๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ, ์ด ์˜ต์…˜์€ ์‹œ์Šคํ…œ์ด ๋„ค์ดํ‹ฐ๋ธŒ ํŒŒ์ผ ์™“์ณ๊ฐ€ ๋ถ€์กฑํ•˜๊ฑฐ๋‚˜/ํ˜น์€ ์ง€์›ํ•˜์ง€ ์•Š์„ ๋•Œ, ์‚ฌ์šฉ๋˜๋Š” ํด๋ง ์ „๋žต์„ ์ง€์ •ํ•ฉ๋‹ˆ๋‹ค. ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์„ค์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
    • fixedPollingInterval: (์œ„๋ฅผ ์ฐธ์กฐํ•˜์„ธ์š”.)
    • priorityPollingInterval: (์œ„๋ฅผ ์ฐธ์กฐํ•˜์„ธ์š”.)
    • dynamicPriorityPolling: (์œ„๋ฅผ ์ฐธ์กฐํ•˜์„ธ์š”.)
  • synchronousWatchDirectory: ๋””๋ ‰ํ„ฐ๋ฆฌ์˜ ์—ฐ๊ธฐ๋œ ๊ฐ์‹œ๋ฅผ ๋น„ํ™œ์„ฑํ™”ํ•ฉ๋‹ˆ๋‹ค. ์—ฐ๊ธฐ๋œ ๊ฐ์‹œ๋Š” ๋งŽ์€ ํŒŒ์ผ์ด ํ•œ ๋ฒˆ์— ๋ณ€๊ฒฝ๋  ๋•Œ ์œ ์šฉํ•ฉ๋‹ˆ๋‹ค (์˜ˆ๋ฅผ ๋“ค์–ด, npm install์„ ์‹คํ–‰ํ•˜์—ฌ node_modules์˜ ๋ณ€๊ฒฝ), ํ•˜์ง€๋งŒ ๋œ-์ผ๋ฐ˜์ ์ธ ์„ค์ •์„ ์œ„ํ•ด ๋น„ํ™œ์„ฑํ™”ํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

์ด ๋ณ€๊ฒฝ์˜ ๋” ์ž์„ธํ•œ ๋‚ด์šฉ์€ Github์œผ๋กœ ์ด๋™ํ•˜์—ฌ the pull request๋ฅผ ์ฝ์–ด๋ณด์„ธ์š”.

"๋น ๋ฅด๊ณ  ๋Š์Šจํ•œ" ์ฆ๋ถ„ ๊ฒ€์‚ฌ

TypeScript 3.8์€ ์ƒˆ๋กœ์šด ์ปดํŒŒ์ผ๋Ÿฌ ์˜ต์…˜ assumeChangesOnlyAffectDirectDepencies์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ์ด ์˜ต์…˜์ด ํ™œ์„ฑํ™”๋˜๋ฉด, TypeScript๋Š” ์ •๋ง๋กœ ์˜ํ–ฅ์„ ๋ฐ›์€ ํŒŒ์ผ๋“ค์€ ์žฌ๊ฒ€์‚ฌ/์žฌ๋นŒ๋“œํ•˜์ง€์•Š๊ณ , ๋ณ€๊ฒฝ๋œ ํŒŒ์ผ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ์ง์ ‘ import ํ•œ ํŒŒ์ผ๋งŒ ์žฌ๊ฒ€์‚ฌ/์žฌ๋นŒ๋“œ ํ•ฉ๋‹ˆ๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด, ๋‹ค์Œ๊ณผ ๊ฐ™์ด fileA.ts๋ฅผ import ํ•œ fileB.ts๋ฅผ import ํ•œ fileC.ts๋ฅผ import ํ•œ fileD.ts๋ฅผ ์‚ดํŽด๋ด…์‹œ๋‹ค:

fileA.ts <- fileB.ts <- fileC.ts <- fileD.ts

--watch ๋ชจ๋“œ์—์„œ๋Š”, fileA.ts์˜ ๋ณ€๊ฒฝ์ด fileB.ts, fileC.ts ๊ทธ๋ฆฌ๊ณ  fileD.ts๋ฅผ TypeScript๊ฐ€ ์žฌ-๊ฒ€์‚ฌํ•ด์•ผ ํ•œ๋‹ค๋Š” ์˜๋ฏธ์ž…๋‹ˆ๋‹ค. assumeChangesOnlyAffectDirectDependencies์—์„œ๋Š” fileA.ts์˜ ๋ณ€๊ฒฝ์€ fileA.ts์™€ fileB.ts๋งŒ ์žฌ-๊ฒ€์‚ฌํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.

Visual Studio Code์™€ ๊ฐ™์€ ์ฝ”๋“œ ๋ฒ ์ด์Šค์—์„œ๋Š”, ํŠน์ • ํŒŒ์ผ์˜ ๋ณ€๊ฒฝ์— ๋Œ€ํ•ด ์•ฝ 14์ดˆ์—์„œ ์•ฝ 1์ดˆ๋กœ ์žฌ๋นŒ๋“œ ์‹œ๊ฐ„์„ ์ค„์—ฌ์ฃผ์—ˆ์Šต๋‹ˆ๋‹ค. ์ด ์˜ต์…˜์„ ๋ชจ๋“  ์ฝ”๋“œ ๋ฒ ์ด์Šค์—์„œ ์ถ”์ฒœํ•˜๋Š” ๊ฒƒ์€ ์•„๋‹ˆ์ง€๋งŒ, ํฐ ์ฝ”๋“œ ๋ฒ ์ด์Šค๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ๊ณ , ๋‚˜์ค‘๊นŒ์ง€ ์ „์ฒด ํ”„๋กœ์ ํŠธ ์˜ค๋ฅ˜๋ฅผ ๊ธฐ๊บผ์ด ์—ฐ๊ธฐํ•˜๊ฒ ๋‹ค๋ฉด (์˜ˆ๋ฅผ ๋“ค์–ด, tsconfig.fullbuild.json์ด๋‚˜ CI๋ฅผ ํ†ตํ•œ ์ „์šฉ ๋นŒ๋“œ) ํฅ๋ฏธ๋กœ์šธ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๋” ์ž์„ธํ•œ ๋‚ด์šฉ์€ the original pull request์—์„œ ๋ณด์‹ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.