1. TSC Transpiler ๐Ÿ‘ฉโ€๐Ÿ’ป

JavaScript ๋Š” Interpreter Language ์ด๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์ด๊ฒƒ์„ ํ™•์žฅํ•œ TypeScript ๋Š” ์›น ๋ธŒ๋ผ์šฐ์ €๊ฐ€ JavaScript ๋งŒ ์ดํ•ดํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ๋ณ€ํ™˜์„ ํ•ด์•ผํ•˜๋Š”๋ฐ ์ด ๊ณผ์ •์„ Transpile ์ด๋ผ ํ•œ๋‹ค.

Compile Language ๊ฐ€ ์•„๋‹ˆ๊ธฐ ๋•Œ๋ฌธ์— Transpile ์ด๋ผ๊ณ  ๊ตฌ๋ถ„์ง“๊ธฐ๋„ ํ•˜๊ณ , ๋‹ค๋ฅธ ์ปดํŒŒ์ผ ์–ธ์–ด์™€ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ Runtime ์ด์ „์— ์˜ค๋ฅ˜๋ฅผ ์ฐพ์•„๋‚ผ ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— Compile ์ด๋ผ ๋ถ€๋ฅด๋Š” ๊ฒฝ์šฐ๋„ ์กด์žฌํ•œ๋‹ค. ์•„๋ฌดํŠผ ์ด๋•Œ ์‚ฌ์šฉ๋˜๋Š” ๊ฒƒ์ด ๋ฐ”๋กœ TSC๋‹ค.

TypeScript ๋Š” Global ๋กœ ์„ค์น˜ํ•˜๊ฑฐ๋‚˜ Local ๋กœ ์„ค์น˜ํ•  ์ˆ˜ ์žˆ๋‹ค. Global ๋กœ ์„ค์น˜ํ–ˆ์„๋•Œ์™€ ๋‹ค๋ฅด๊ฒŒ Local ๋กœ ์„ค์น˜ํ–ˆ์„ ๊ฒฝ์šฐ ๊ฒฝ๋กœ๋ฅผ ์ง€์ •ํ•ด์ค˜์•ผํ•˜๋ฉฐ ๋‹ค์Œ ๋‘˜ ์ค‘ ํ•˜๋‚˜๋ฅผ ์ด์šฉํ•ด ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๋‹ค.

./node_modules/.bin/tsc --init
./node_modules/typescript/bin/tsc --init


๊ทธ ์™ธ์—๋„ npx๋ฅผ ์‚ฌ์šฉํ•˜๊ฑฐ๋‚˜

npx tsc

package.jsonํŒŒ์ผ์„ ์‚ฌ์šฉํ•ดํ•  ์ˆ˜ ์žˆ๋Š”๋ฐ, ์ด๋•Œ๋Š” NPM Project ๋กœ ๋งŒ๋“ค์—ˆ๊ธฐ ๋•Œ๋ฌธ์—tsc๋ผ๊ณ ๋งŒ ์ณ๋„ Local ๋กœ ์„ค์น˜ํ•œ ํŒจํ‚ค์ง€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์ธ์‹ํ•  ์ˆ˜ ์žˆ๋‹ค.

{
  "scripts": {
    "build": "tsc"
  }
}

2. Basic Types ๐Ÿ‘ฉโ€๐Ÿ’ป

1. Types

ECMAScript Types

  • Boolean
  • Number
  • String
  • Symbol (ECMAScript 6 ์ถ”๊ฐ€)
  • Null
  • Undefined
  • Array (์‹ค์ œ๋กœ๋Š” Object)

TypeScript Types

  • Any, Void, Never, Unknown
  • Enum
  • Tuple (์‹ค์ œ๋กœ๋Š” Object)

2. Primitive Types

Object ์™€ Reference ํ˜•ํƒœ๊ฐ€ ์•„๋‹Œ ์‹ค์ œ ๊ฐ’์„ ์ €์žฅํ•˜๋Š” ์ž๋ฃŒํ˜•์„ ๋งํ•œ๋‹ค.

  • boolean
  • number
  • string
  • symbol (ES2015)
  • null
  • undefined

JavaScript ์˜ ์ฒ˜๋ฆฌ ๋ฐฉ์‹์œผ๋กœ Primitive Types ์— ๋‚ด์žฅ ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•˜๋‹ค.

let name = 'Mark'
name.toString()


Primitive Types ๋Š” literal ๊ฐ’์œผ๋กœ Primitive Types ์˜ Sub Types ๋ฅผ ๋‚˜ํƒ€๋‚ผ ์ˆ˜ ์žˆ๋‹ค.

true      // Primitive Type `boolean`์˜ `Sub Type` 
'hello'
3.14
null
undefined

new๋ฅผ ์‚ฌ์šฉํ•ด Wrapper Object ๋กœ ๋งŒ๋“  Types ๋Š” Primitive Types ๊ฐ€ ์•„๋‹ˆ๊ณ  Object ๋‹ค.

new Boolean(false)    // typeof new Boolean(false) : 'object'
new String( 'world')  // typeof new String('world') : 'object'
new Number (42)       // typeof new Number (42) : 'object'

Type Casting

๋‹ค๋ฅธ ์–ธ์–ด์—์„œ String ๊ณผ ๊ฐ™์€ ํƒ€์ž…์„ ๋‚˜ํƒ€๋‚ผ ๋•Œ ๋Œ€๋ฌธ์ž๋กœ ํ‘œํ˜„ํ•˜๋Š” ๊ฒƒ๊ณผ ๋‹ฌ๋ฆฌ TypeScript ๋Š” Object Types ์™€ ๊ตฌ๋ถ„ํ•˜๊ธฐ ์œ„ํ•ด Primitive Types ๋ฅผ ๋ชจ๋‘ Lower-case๋กœ ํ‘œํ˜„ํ•œ๋‹ค.

3. boolean

let isDone: boolean = false;
isDone = true;

console.log(typeof isDone); // 'boolean'

4. number

JavaScript ์™€ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ TypeScript ์˜ ๋ชจ๋“  ์ˆซ์ž๋Š” ๋ถ€๋™ ์†Œ์ˆ˜์ (Floating Point) ๊ฐ’์ด๋‹ค.

let decimal: number = 6;     // 10์ง„์ˆ˜ ๋ฆฌํ„ฐ๋Ÿด
let hex: number = 0xf00d;    // 16์ง„์ˆ˜ ๋ฆฌํ„ฐ๋Ÿด
let binary: number = 0b1010; // 2์ง„์ˆ˜ ๋ฆฌํ„ฐ๋Ÿด
let octal: number = 0o744;   // 8์ง„์ˆ˜ ๋ฆฌํ„ฐ๋Ÿด

let notANumber: number = NaN;
let underscoreNum: number = 1_000_000;

5. string

JavaScript ์™€ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ Template String ์„ ์ง€์›ํ•œ๋‹ค.

let fullName: string = 'Harry Potter';
let age: number = 17;

let sentence: string = `Hello, My name is ${fullName}.

I'll be ${age + 1} years old next month.`;

console.log(sentence);
Hello, My name is Harry Potter.

I'll be 18 years old next month.

6. symbol

  • ECMAScript2015 ์˜ Symbol ๋กœ new Symbol๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๋‹ค. Symbol ์„ ํ•จ์ˆ˜๋กœ ์‚ฌ์šฉํ•ด์„œ symbol Type ์„ ๋งŒ๋“ค์–ด ๋‚ผ ์ˆ˜ ์žˆ๋‹ค.
  • Primitive Types ์˜ ๊ฐ’์„ ๋‹ด์•„์„œ ์‚ฌ์šฉํ•˜๋ฉฐ, Uniqueํ•˜๊ณ , Immutableํ•œ ๊ฐ’์„ ๋งŒ๋“ค์–ด ์ฃผ๋กœ ์ ‘๊ทผ์„ ์ œ์–ดํ•˜๋Š”๋ฐ ์‚ฌ์šฉ๋œ๋‹ค.
console.log(Symbol('foo') === Symbol('foo')); // false
const sym = Symbol();

const obj = {
  [sym]: 'value',
};

// console.log(obj['sym']); // TypeError
console.log(obj[sym]);

7. null & undefined

tsconfig ์„ค์ •์„ ํ•˜์ง€ ์•Š์œผ๋ฉด null๊ณผ undefined๋Š” ๋‹ค๋ฅธ ๋ชจ๋“  ํƒ€์ž…์˜ subtypes๋กœ ์กด์žฌํ•œ๋‹ค.

let name: string = null;
let age: number = undefined;


์ปดํŒŒ์ผ ์˜ต์…˜์—์„œ --stringNullChecks๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด null์€ ์ž๊ธฐ ์ž์‹ ์—๊ฒŒ๋งŒ, undefined๋Š” ์ž๊ธฐ ์ž์‹ ๊ณผ void์—๊ฒŒ๋งŒ ํ• ๋‹นํ•  ์ˆ˜ ์žˆ๋‹ค. ๋งŒ์•ฝ ๋‹ค๋ฅธ ํƒ€์ž…์ด ํ• ๋‹นํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•˜๋ ค๋ฉด Union Types๋ฅผ ์‚ฌ์šฉํ•ด์•ผํ•œ๋‹ค.

let n: null = null;
let v1: void = null; // TypeError

let u: undefined = undefined
let v2: void = undefined;


null

  • null์ด๋ผ๋Š” ๊ฐ’์œผ๋กœ ํ• ๋‹น๋œ ๊ฒƒ์„ null์ด๋ผ๊ณ  ํ•œ๋‹ค.
  • ๋ฌด์–ธ๊ฐ€๊ฐ€ ์žˆ๋Š”๋ฐ, ์‚ฌ์šฉํ•  ์ค€๋น„๊ฐ€ ๋œ ๋œ ์ƒํƒœ.
  • null type ์€ null ์ด๋ผ๋Š” ๊ฐ’๋งŒ ๊ฐ€์งˆ ์ˆ˜ ์žˆ๋‹ค.
  • Runtime ์—์„œ typeof ์—ฐ์‚ฐ์ž๋ฅผ ์ด์šฉํ•ด ์•Œ์•„๋‚ด๋ฉด, object๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค.
let n: null = null;

console.log(n); // null
console.log(typeof n); // object


undefined

  • ๊ฐ’์„ ํ• ๋‹นํ•˜์ง€ ์•Š์€ ๋ณ€์ˆ˜๋Š” undefined๋ผ๋Š” ๊ฐ’์„ ๊ฐ–๋Š”๋‹ค.
  • ๋ฌด์–ธ๊ฐ€๊ฐ€ ์•„์˜ˆ ์ค€๋น„๊ฐ€ ์•ˆ ๋œ ์ƒํƒœ.
  • Object์˜ Properties ๊ฐ€ ์—†์„ ๋•Œ๋„ undefined๋ฅผ ๊ฐ–๋Š”๋‹ค.
  • Runtime ์—์„œ typeof ์—ฐ์‚ฐ์ž๋ฅผ ์ด์šฉํ•ด ์•Œ์•„๋‚ด๋ฉด, undefined๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค.
let u: undefined = undefined;

console.log(u);  // undefined
console.log(typeof u); // undefined

8. object

TypeScript ์˜ object๋Š” ์šฐ๋ฆฌ๊ฐ€ ๊ฐ์ฒด๋ผ ๋ถ€๋ฅด๋Š” ๊ฒƒ๊ณผ๋Š” ์กฐ๊ธˆ ๋‹ค๋ฅด๊ฒŒ ์‚ฌ์šฉ๋œ๋‹ค. TypeScript ์—์„œ object๋Š” Primitive Types ๊ฐ€ ์•„๋‹Œ ๊ฒƒ์„ ๋‚˜ํƒ€๋‚ด๊ณ  ์‹ถ์„ ๋•Œ ์‚ฌ์šฉํ•˜๋Š” ํƒ€์ž…์ด๋‹ค.

Non-Primitive Types

number, string, boolean, bigint, symbol, null, undefined ๊ฐ€ ์•„๋‹Œ ๊ฒƒ

// created by object literal
const person1 = {
  name: 'Mark',
  age: 25,
};

// created by Object.create
const person2 = Object.create({
  name: 'Mark',
  age: 25,
});

์ฆ‰, Object.create๋Š” Parameters ๋กœ object ๋˜๋Š” null์„ ๋ฐ›์„ ์ˆ˜ ์žˆ๋‹ค. ๋˜ํ•œ JavaScript ์—์„œ Array ๋Š” Object ์˜ ์ผ์ข…์ด๊ธฐ ๋•Œ๋ฌธ์— Array ์—ญ์‹œ ๋„ฃ์„ ์ˆ˜ ์žˆ๋‹ค.

9. Array

  • ๊ฐ™์€ ํƒ€์ž…์˜ elements ๋ฅผ ๋ชจ์•„ ๋†“์€ ์ž๋ฃŒํ˜•์„ ์˜๋ฏธํ•œ๋‹ค.
  • ๋‹ค๋ฅธ ์–ธ์–ด์™€ ๋‹ฌ๋ฆฌ anyํƒ€์ž…์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ณ ๋„ unionํƒ€์ž…์„ ์‚ฌ์šฉํ•ด ์„œ๋กœ ๋‹ค๋ฅธ ํƒ€์ž…์˜ elements ๋ฅผ ๋ชจ์•„ ๋ฐฐ์—ด์„ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‹ค.
let list1: number[] = [1, 2, 3, 4, 5];
let list2: Array<number> = [1, 2, 3, 4, 5];
let list3: (number | string)[] = [1, '2', 3, '4', 5];
let list4: Array<number | string> = [1, '2', 3, '4', 5];

10. Tuple

JavaScript ์— tuple์ด ์กด์žฌํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— Array ๋ฅผ ์‚ฌ์šฉํ•ด ๊ตฌํ˜„ํ•œ๋‹ค.

let person1: [string, number] = ['Mark', 25];
let person2: Array<string | number> = ['Mark', 25];

const [name, age] = ['Mark', 25];

11. any

  • ํƒ€์ž…์ด ์ •ํ•ด์ง€์ง€ ์•Š์•„ ๋ถˆ๊ฐ€๋Šฅํ•˜๋‹ค๋Š” ๊ฒƒ์ด ์•„๋‹Œ ์–ด๋–ค ํƒ€์ž…์ด์–ด๋„ ์ƒ๊ด€ ์—†๋Š” ํƒ€์ž…์œผ๋กœ any.toString()๊ฐ™์€ ๊ฒƒ์„ ํ•ด๋„ ์—๋Ÿฌ๋กœ ์ธ์‹ํ•˜์ง€ ์•Š๋Š”๋‹ค.
  • ๋”ฐ๋ผ์„œ Compiler ๊ฐ€ ์—๋Ÿฌ๋ฅผ ์‚ฌ์ „์— ํ™•์ธํ•  ์ˆ˜ ์—†๊ธฐ ๋•Œ๋ฌธ์— ์ตœ๋Œ€ํ•œ ์‚ฌ์šฉํ•˜์ง€ ์•Š์•„์•ผ ํ•œ๋‹ค.
  • noImplicitAny ์˜ต์…˜์€ any๋ฅผ ์˜๋„์ ์œผ๋กœ ํ‘œํ˜„ํ•˜๊ฑฐ๋‚˜ ๋ช…ํ™•ํ•œ ํƒ€์ž…์„ ์ง€์ •ํ•˜๋„๋ก ๊ฐ•์ œํ•ด ๊ฐœ๋ฐœ์ž๊ฐ€ ์•ˆ์ „ํ•œ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๋„๋ก ํ•œ๋‹ค.
function returnAny(message: any) {
  console.log(message);
}

์œ„์™€ ๊ฐ™์€ ๊ฒฝ์šฐ ๋ณ„๋‹ค๋ฅธ ์ƒํ˜ธ์ž‘์šฉ์„ ํ•˜๊ฑฐ๋‚˜ ์—๋Ÿฌ๋ฅผ ๋ฐœ์ƒ์‹œํ‚ค์ง€ ์•Š์œผ๋ฏ€๋กœ ๊ฐœ๋ฐœ์ž๊ฐ€ ๋ช…์‹œ์ ์œผ๋กœ any๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. ์ฆ‰, any๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค๋Š” ๊ฒƒ์€ ์ด๊ฒƒ์ด ์—๋Ÿฌ๋ฅผ ๋ฐœ์ƒ์‹œํ‚ค์ง€ ์•Š์Œ์— ๋Œ€ํ•œ ์ฑ…์ž„์ด ๊ฐœ๋ฐœ์ž์—๊ฒŒ ์ฃผ์–ด์ง„๋‹ค.


์–ด๋–ค ํƒ€์ž…์ด ๋“ค์–ด์˜ฌ์ง€ ๋ชจ๋ฅด๊ฑฐ๋‚˜ ๊ท€์ฐฎ์•„ any๋ฅผ ์‚ฌ์šฉํ•˜๋ ค ํ•œ๋‹ค๋ฉด ๋ฐ˜๋“œ์‹œ unionํƒ€์ž…์„ ์‚ฌ์šฉํ•˜๋„๋ก ๊ณ ์ณ์•ผ ํ•œ๋‹ค.
any ๋Š” object ๋ฅผ ํ†ตํ•ด ๊ณ„์†ํ•ด์„œ ์ „ํŒŒ๋˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

let anyType: any = {};

let alsoAny = anyType.a.b.c.d.e;

์ด๊ฒƒ์€ Optional Chaining ๊ณผ ์œ ์‚ฌํ•˜๋‹ค๋Š” ๊ฒƒ์„ ์•Œ ์ˆ˜ ์žˆ๋‹ค. ๊ฐ์ฒด์˜ ์–ด๋–ค property ์— ์ ‘๊ทผํ•˜๊ธฐ ์œ„ํ•ด ๋‹จ ํ•œ ๋ฒˆ์ด๋ผ๋„ Optional Chaining ์„ ํ•˜๊ฒŒ ๋˜๋ฉด, ๊ฒฐ๊ณผ๋Š” ํ•ญ์ƒ Optional ์ธ ๊ฒƒ์ฒ˜๋Ÿผ, Object ์— ๋‹จ ํ•œ ๋ฒˆ์ด๋ผ๋„ any ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด, ๊ฒฐ๊ณผ๋Š” ํ•ญ์ƒ any ๊ฐ€ ๋œ๋‹ค.


์œ„์™€ ๊ฐ™์€ any ์ „ํŒŒ๋กœ ์ธํ•œ ๋ˆ„์ˆ˜๋ฅผ ๋ง‰๊ธฐ ์œ„ํ•ด ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ค‘๊ฐ„์— ํƒ€์ž…์„ ์ง€์ •ํ•  ์ˆ˜ ์žˆ๋‹ค.

function leakingAny(obj: any) {
  const a = obj.num;
  const b = a + 1;
  return b;
}

const something = leakingAny({ num: 10 });
something.indexOf('0');

something ์ด anyํƒ€์ž…์ด๊ธฐ ๋•Œ๋ฌธ์— ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•˜์ง€ ์•Š๋Š”๋‹ค.

function leakingAny(obj: any) {
  const a: number = obj.num;
  const b = a + 1;
  return b;
}

const something = leakingAny({ num: 10 });
something.indexOf('0');  // error, Property 'indexOf' does not exist on type 'number'

a ๋ฅผ number๋กœ ํƒ€์ž…์„ ์ง€์ •ํ•˜๋Š” ์ˆœ๊ฐ„ b ์™€ something ์—ญ์‹œ numberํƒ€์ž…์œผ๋กœ ์ง€์ •๋œ๋‹ค. ๋”ฐ๋ผ์„œ number๋Š” indexOf๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ์ปดํŒŒ์ผ๋Ÿฌ๋Š” ์—๋Ÿฌ๋ฅผ ๊ฐ์ง€ํ•œ๋‹ค. ์ฆ‰, any ๋ˆ„์ˆ˜๋ฅผ ๋ง‰์€ ๊ฒƒ์ด๋‹ค. ํ•˜์ง€๋งŒ ์ด์™€ ๊ฐ™์€ ๋ฐฉ์‹์œผ๋กœ any ๋ˆ„์ˆ˜๋ฅผ ๋ง‰๋Š” ๊ฒƒ์€ ์ข‹์€ ๋ฐฉ๋ฒ•์ด ์•„๋‹ˆ๋‹ค. Type Guard ๋ฅผ ์‚ฌ์šฉํ•ด unknown์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์ข‹์€ ๋ฐฉ๋ฒ•์ด๋‹ค.

12. unknown

์•ฑ์„ ๋งŒ๋“ค๋‹ค ๋ณด๋ฉด ๋™์  ์ฝ˜ํ…์ธ ์™€ ๊ฐ™์ด ์˜๋„์ ์œผ๋กœ ๋ชจ๋“  ๊ฐ’์„ ์ˆ˜๋ฝํ•˜๊ธฐ๋ฅผ ์›ํ•˜๊ฑฐ๋‚˜ ์ž‘์„ฑํ•  ๋•Œ ๋ชจ๋ฅด๋Š” ๋ณ€์ˆ˜์˜ ํƒ€์ž…์„ ๋ฌ˜์‚ฌํ•ด์•ผ ํ•  ์ˆ˜๋„ ์žˆ๋‹ค. ์ด ๊ฒฝ์šฐ any๋ฅผ ์‚ฌ์šฉํ•ด Any Leaking ์œ„ํ—˜์„ ๊ฐ์ˆ˜ํ•˜๋Š” ๋Œ€์‹  Compiler ์™€ ๋‹ค๋ฅธ ์‚ฌ๋žŒ์—๊ฒŒ ์ด๋ฅผ ์˜๋„์ ์œผ๋กœ ์ด ๋ณ€์ˆ˜๊ฐ€ ๋ฌด์—‡์ด๋“  ๋  ์ˆ˜ ์žˆ์Œ์„ ์•Œ๋ ค์ฃผ๋Š” ํƒ€์ž…์œผ๋กœ unknownํƒ€์ž…์„ ์ œ๊ณตํ•œ๋‹ค.

unknownํƒ€์ž…์€ any์™€ ๋น„์Šทํ•˜์ง€๋งŒ Type-Safeํ•œ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ๋„๋ก Compiler ๊ฐ€ ์ด๋ฅผ ์ฝ”๋“œ๋ฅผ ๊ฐ์‹œํ•  ์ˆ˜ ์žˆ๋‹ค. unknownํƒ€์ž…์€ ์‚ฌ์šฉํ•˜๋ ค๋ฉด Type Guard ๋ฅผ ์‚ฌ์šฉํ•ด

declare const maybe: unknown;

if (typeof maybe === 'number') {
  const aNumber: number = maybe;
}

TypeScript ์˜ unknownํƒ€์ž…๊ณผ Type Guard ๋Š” Swift ์˜ Any ํƒ€์ž…๊ณผ Upcating Operator โ€˜asโ€™ ์™€ ์œ ์‚ฌํ•˜๋‹ค.

var things: [Any] = []

func testAnyTypes(_ things: [Any]) {
    for thing in things {
        switch thing {
        case 0 as Int:
            print("\(thing) : zero as an Int")
        case 0 as Double:
            print("\(thing) : zero as a Double")
        case let someInt as Int:
            print("\(thing) : an integer value of \(someInt)")
        case let someDouble as Double where someDouble > 0:
            print("\(thing) : a positive double value of \(someDouble)")
        case is Double:
            print("some other double value that I don't want to print")
        case let someString as String:
            print("\(thing) : a string value of \"\(someString)\"")
        case let (x, y) as (Double, Double):
            print("\(thing) : an (x, y) point at \(x), \(y)")
        case let stringConverter as (String) -> String:
            print("\(thing) : \(stringConverter("Michael"))")
        case let movie as Movie:
            print("\(thing) : a movie called \(movie.name), dir. \(movie.director)")
        case let point as Point:
            print("\(thing) : a point is at (\(point.x), \(point.y))")
        case let direction as CompassPoint:
            print("\(thing) : a direction is \(direction)")
        default:
            print("\(thing) : something else")
        }
    }
}

13. never

๋ณดํ†ต return์— ์‚ฌ์šฉ๋œ๋‹ค.

  • null, undefined์™€ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ๋‹ค๋ฅธ ๋ชจ๋“  ํƒ€์ž…์˜ subtypes๋กœ ์กด์žฌํ•œ๋‹ค.
  • never๋Š” ์ฃผ๋กœ return์— ์‚ฌ์šฉ๋˜๋ฉฐ, ๋ชจ๋“  ํƒ€์ž…์— ํ• ๋‹นํ•  ์ˆ˜ ์žˆ๋‹ค. ํ•˜์ง€๋งŒ never์—๋Š” any๋ฅผ ํฌํ•จํ•ด ๊ทธ ์–ด๋Š ๊ฒƒ๋„ ํ• ๋‹นํ•  ์ˆ˜ ์—†๋‹ค.
  • never์˜ ์ด๋Ÿฐ ํŠน์„ฑ์„ ์ด์šฉํ•ด Type Guard ๋˜๋Š” Conditional Types ์— ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.


never๋Š” ๊ฐ’์ด ์•„๋‹Œ ํƒ€์ž…์œผ๋กœ๋งŒ ์‚ฌ์šฉ๋  ์ˆ˜ ์žˆ๋‹ค

function error(message: string): never {
  throw new Error(message);
}

function fail(message: string) {
  return error(message);
}


Type Guard ์— ์‚ฌ์šฉ๋˜๊ธฐ๋„ ํ•œ๋‹ค

declare const a: string;

if (typeof a !== 'string') {
  a; // never
}

declare const b: string | number;

if (typeof b !=='string') {
  b; // number
}


Conditional Types ์— ์‚ฌ์šฉ๋˜๊ธฐ๋„ ํ•œ๋‹ค

type MessageOf<T extends { message: unknown }> = T['message'];

interface Email {
  message: string;
}

type EmailMessageContent = MessageOf<Email>;
// type EmailMessageContent = string

์œ„ ์ฝ”๋“œ์—์„œ MessageOf๊ฐ€ ์•„๋ฌด ํƒ€์ž…์ด๋‚˜ ๋ฐ›์„ ์ˆ˜ ์žˆ๋„๋ก ํ•˜๋ ค๋ฉด neverํƒ€์ž…์„ ์‚ฌ์šฉํ•ด ๋‹ค์Œ๊ณผ ๊ฐ™์ด Conditional Types๋กœ ๋ฐ”๊ฟ€ ์ˆ˜ ์žˆ๋‹ค.

  • Destructuring
type MessageOf<T> = T extends { message: unknown } ? T['message'] : never;

interface Email {
  message: string;
}

type EmailMessageContent = MessageOf<Email>;
// type EmailMessageContent = string

interface Dog {
  bark(): void;
}

type DogMessageContent = MessageOf<Dog>;
// type DogMessageContent = never
  • Flatten
type Flatten<T> = T extends any[] ? T[number] : T;
// type Flatten<T> = T extends Array<infer Item> ? Item : T;

type Str = Flatten<string[]>;
// type Str = string;

type Num = Flatten<number[]>;
// type Num = number;

type Something = Flatten<object>;
// type Something = object;

type K = Flatten<[string, number]>;
// type K = string | number;
  • To Array
type ToArray<Type> = Type extends any ? Type[] : never;

type StrArr = ToArray<string>;
// type StrArr = string[];

type StrArrOrNumArr = ToArray<string | number>;
// type StrArrOrNumArr = string[] | number[];
  • To Array Non-distributed
type ToArrayNonDist<Type> = [Type] extends [any] ? Type[] : never;

type StrArr = ToArrayNonDist<string>;
// type StrArr = string[];

type ArrOfStrOrNum = ToArrayNonDist<string | number>;
// type ArrOfStrOrNum = (string | number)[];

14. void

๊ฐ’์„ ๋ฐ˜ํ™˜ํ•˜์ง€ ์•Š๋Š” ํ•จ์ˆ˜์˜ Return Type์œผ๋กœ ์‚ฌ์šฉํ•œ๋‹ค. ๋‹ค๋ฅธ ์–ธ์–ด์™€ ๋ฌธ๋ฒ•์ ์ธ ํ†ต์ผ์„ฑ์„ ์œ„ํ•ด ์ถ”๊ฐ€๋œ ํƒ€์ž…์œผ๋กœ JavaScript ์— ์ด๋ฏธ ์กด์žฌํ•˜๋Š” undefined๋ผ๋Š” ํƒ€์ž…๊ณผ ๋™์ผํ•˜๋‹ค. ํ•จ์ˆ˜์˜ Return Type ์œผ๋กœ ์‚ฌ์šฉ๋˜๋Š” undefined ์ •๋„๋กœ ๋ณด๋ฉด ๋œ๋‹ค.

function returnVoid(message: string) {
  console.log(message);
}
// function returnVoid(message: string): void

const r = returnVoid('no return');
console.log(r); // undefined

void๋Š” ์‚ฌ์‹ค undefined์™€ ๊ฐ™๋‹ค. ํ•˜์ง€๋งŒ ๋ช…์‹œ์ ์œผ๋กœ undefined์— ํ• ๋‹นํ•˜๋Š” ๊ฒƒ์€ ๋ถˆ๊ฐ€๋Šฅํ•˜๋‹ค.

const r: undefined = returnVoid('no return');  // error, Type 'void' is not assignable to type 'undefined'

์ด๋กœ์จ TypeScript ์˜ void ์—ญ์‹œ ๋‹ค๋ฅธ ์–ธ์–ด์˜ void์™€ ์œ ์‚ฌํ•˜๊ฒŒ ์ž‘๋™ํ•œ๋‹ค.


3. Type System ๐Ÿ‘ฉโ€๐Ÿ’ป

1. Make TypeScript more Strictly

TypeScript ๋Š” ์ง์ ‘ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๋Š” ์–ธ์–ด๊ฐ€ ์•„๋‹ˆ๊ณ  ์ตœ์ข…์ ์œผ๋กœ JavaScript ๋กœ ๋ณ€ํ™˜๋˜์–ด์•ผ ํ•˜๋Š” ์–ธ์–ด์ด๊ธฐ ๋•Œ๋ฌธ์— ๊ฐ–๋Š” ๋ช‡ ๊ฐ€์ง€ ํ•œ๊ณ„๊ฐ€ ์žˆ๋‹ค. ์–ด๋–ค ํ•œ๊ณ„๊ฐ€ ์žˆ๋Š”์ง€, ๊ทธ๋ฆฌ๊ณ  ์–ด๋–ป๊ฒŒ ํ•˜๋ฉด ์ด ๋ฌธ์ œ๋ฅผ compile-error ๋ฅผ ๋ฐœ์ƒ์‹œ์ผœ ๋ฏธ๋ฆฌ ์˜ˆ๋ฐฉํ•  ์ˆ˜ ์žˆ๋Š”์ง€ ์•Œ์•„๋ณด์ž.


noImplicitAny

function foo(a) {
  return a * 10
}

noImplicitAny ์˜ต์…˜์€ ์œ„์™€ ๊ฐ™์ด ์ž…๋ ฅ๊ฐ’์„ any๋กœ ๋ฐ›์„ ์ˆ˜ ์žˆ๋Š” ์ƒํ™ฉ์— ๋Œ€ํ•ด compile-error ๋ฅผ ๋ฐœ์ƒ์‹œ์ผœ ๋ช…์‹œ์ ์œผ๋กœ ํƒ€์ž…์„ ์ง€์ •ํ•˜๋„๋ก ๊ฐ•์ œํ•œ๋‹ค.


strictNullChecks & noImplicitReturns

function foo(a: number) {
  if (a > 0) {
    return a * 10
  }
}

์ด ๊ฒฝ์šฐ a ์˜ ํƒ€์ž…์ด ์ง€์ •๋˜๋ฉฐ Return Type ์ด number ๋กœ ์ถ”๋ก ๋œ๋‹ค. ํ•˜์ง€๋งŒ a ๊ฐ€ ์–‘์ˆ˜๊ฐ€ ์•„๋‹ ๊ฒฝ์šฐ void๋ฅผ ๋ฐ˜ํ™˜ํ•˜๊ฒŒ๋œ๋‹ค. ์ฆ‰, foo(-5) + 10์„ ํ•˜๊ฒŒ ๋˜๋ฉด undefined + 5๊ฐ€ ๋˜๋ฏ€๋กœ NaN์ด ๋œ๋‹ค.

์ด๋กœ์จ TypeScript ์˜ number๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ undefined๋ฅผ ํฌํ•จํ•˜๊ณ  ์žˆ์Œ์„ ์•Œ ์ˆ˜ ์žˆ๋‹ค. strictNullChecks ์˜ต์…˜์€ ๋ชจ๋“  ํƒ€์ž…์— ์ž๋™์œผ๋กœ ํฌํ•จ๋˜์–ด์žˆ๋Š” null๊ณผ undefined๋ฅผ ์ œ๊ฑฐํ•œ๋‹ค. ๋˜ํ•œ noImplicitReturns ์˜ต์…˜์€ ์œ„์™€ ๊ฐ™์€ ๋ฆฌํ„ด๊ฐ’ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒ๋˜์ง€ ์•Š๋„๋ก Return Type ์ด ์กด์žฌํ•˜๋Š” ๊ฒฝ์šฐ ๋ช…์‹œ์ ์œผ๋กœ ํƒ€์ž…์„ ์ง€์ •ํ•˜๋„๋ก ๊ฐ•์ œํ•œ๋‹ค.

function foo(a: number): number {
  if (a > 0) {
    return a * 10;
  } else {
    throw new Error("Input must be a positive number");
  }
}

2. Structural Type System & Nominal Type System

  • Structural Type System: ๊ตฌ์กฐ๊ฐ€ ๊ฐ™์œผ๋ฉด ๊ฐ™์€ ํƒ€์ž….
  • Nominal Type System: ๊ตฌ์กฐ๊ฐ€ ๊ฐ™์•„๋„ ์ด๋ฆ„์ด ๋‹ค๋ฅด๋ฉด ๋‹ค๋ฅธ ํƒ€์ž….


Structural Type System

interface IPerson {
  name: string;
  age: number;
  speak(): string;
}

type PersonType = {
  name: string;
  age: number;
  speak(): string;
}

let personInterface: IPerson = {} as any;
let  personType: PersonType = {} as any;

์œ„ ๋‘ ํƒ€์ž…์€ ๋ฌธ๋ฒ•์  ์ฐจ์ด๋Š” ์žˆ์ง€๋งŒ ๋ฐ์ดํ„ฐ๋ฅผ ํ• ๋‹นํ•  ๋•Œ ๋™์ผํ•œ ํƒ€์ž…์œผ๋กœ ๊ฐ„์ฃผ๋œ๋‹ค(ํƒ€์ž…์„ ํ™•์žฅํ•˜๊ฑฐ๋‚˜ ํ•  ๋•Œ ๋ฌธ๋ฒ•์  ์ฐจ์ด๋Š” ์กด์žฌํ•œ๋‹ค).


Nominal Type System

C์™€ ๊ฐ™์€ ์–ธ์–ด๋Š” ๊ตฌ์กฐ๊ฐ€ ๊ฐ™์•„๋„ ์ด๋ฆ„์ด ๋‹ค๋ฅด๋ฉด ๋‹ค๋ฅธ ํƒ€์ž…์ด๋‹ค. ์ฆ‰, TypeScript ๋Š” ์ด๋Ÿฌํ•œ ํƒ€์ž… ์‹œ์Šคํ…œ์„ ๋”ฐ๋ฅด์ง€ ์•Š๋Š”๋‹ค. ๋งŒ์•ฝ, ์ด๋Ÿฌํ•œ ํƒ€์ž…์ด ํ•„์š”ํ•  ๊ฒฝ์šฐ ๋‹ค์Œ๊ณผ ๊ฐ™์ด symbol์„ ์ด์šฉํ•ด ์œ ์‚ฌํ•œ ๊ตฌํ˜„์€ ๊ฐ€๋Šฅํ•˜๋‹ค.

type PersonId = string & { readonly brand: unique symbol }

function PersonId(id: string): PersonId {
  // id ๊ฒ€์ฆ ๋กœ์ง...
  
  return id as PersonId;
}

function getPersonById(id: PersonId) { }

getPersonById(PersonId('id-327364'));
getPersonById('id-327364');  // error TS2345

์œ„์™€ ๊ฐ™์€ ๋ฐฉ๋ฒ•์œผ๋กœ ๊ฐ™์€ ํ˜•ํƒœ์ง€๋งŒ ๋‹ค๋ฅธ ๊ณ ์œ ํ•œ ํƒ€์ž…์œผ๋กœ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‹ค.

3. Type Compatibility

// sub1 ํƒ€์ž…์€ sup1 ํƒ€์ž…์˜ `Sub-Type`์ด๋‹ค.
let sub1: 1 = 1;
let sup1: number = sub1;
sub1 = sup1; // error

// sub2 ํƒ€์ž…์€ sup2 ํƒ€์ž…์˜ `Sub-Type`์ด๋‹ค.
let sub2: number[] = [1];
let sup2: object = sub2;
sup2 = sup2; // error

// sub3 ํƒ€์ž…์€ sup3 ํƒ€์ž…์˜ `Sub-Type`์ด๋‹ค.
let sub3: [number, number] = [1, 2];
let sup3: number[] = sub3;
sub3 = sup3; // error

TypeScript ์˜ ํƒ€์ž… ํ˜ธํ™˜์„ฑ์€ ์œ„์™€ ๊ฐ™์ด ๋‹ค๋ฅธ ์–ธ์–ด๋“ค๊ณผ ํฌ๊ฒŒ ๋‹ค๋ฅด์ง€ ์•Š๋‹ค. ํ•˜์ง€๋งŒ function์˜ ํƒ€์ž…์— ๋Œ€ํ•ด์„œ ํ•˜์œ„ ํ˜ธํ™˜ ๋ฟ ์•„๋‹ˆ๋ผ ์ƒ์œ„ ํ˜ธํ•œ๊นŒ์ง€ ๋œ๋‹ค, ์ตœ์ข… Runtime Code ์ธ JavaScript ์—์„œ ์ด๋Ÿฐ ๊ฒƒ์ด ๊ฐ€๋Šฅํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

class Person {}
class Developer extends Person { }
class JuniorDeveloper extends Developer { }

function tellMe(f: (d: Developer) => Developer) {}

// Parameter ์— Developer => Developer ๋ฅผ ์ „๋‹ฌ.
tellMe((d: Developer): Developer => new Developer())  // OK

// Parameter ์— Person => Developer ๋ฅผ ์ „๋‹ฌ.
tellMe((p: Person): Developer => new Developer())  // Super-Type ์— ์˜ํ•œ Sub-Type ํ•˜์œ„ ํ˜ธํ™˜

// Parameter ์— JuniorDeveloper => Developer ๋ฅผ ์ „๋‹ฌ.
tellMe((j: JuniorDeveloper): Developer => new Developer())  // Sub-Type ์ด Super-Type ์„ ์ƒ์œ„ ํ˜ธํ™˜

tellMe์˜ 3๋ฒˆ์งธ ํ˜ธ์ถœ์€ ๋‹ค๋ฅธ ์–ธ์–ด์—์„œ ๋ณด๋ฉด ๋ถ„๋ช… ์ž˜๋ชป๋œ ํ˜ธ์ถœ์ด๋‹ค. ํ•˜์ง€๋งŒ TypeScript ์—์„œ๋Š” ์ด๊ฒƒ์ด ๊ฐ€๋Šฅํ•˜๋ฉฐ, ์‹ฌ์ง€์–ด ์—๋Ÿฌ๊ฐ€ ์•„๋‹ˆ๋‹ค. Make TypeScript more Strictly ์—์„œ ๋ณธ ๊ฒƒ์ฒ˜๋Ÿผ ์ด๊ฒƒ ์—ญ์‹œ compile-error ๋ฅผ ๋ฐœ์ƒ์‹œํ‚ฌ ์ˆ˜ ์žˆ๋Š”๋ฐ, strictFunctionTypes ์˜ต์…˜์„ ํ™œ์„ฑํ™” ํ•˜๋ฉด ๋œ๋‹ค.

๋”ฐ๋ผ์„œ TypeScript ์—์„œ noImplicitAny, strictNullChecks, noImplicitReturns, strictFunctionTypes ์ด 4๊ฐœ์˜ ์˜ต์…˜์€ ์•ˆ์ „ํ•œ ์ฝ”๋“œ ์ž‘์„ฑ์„ ์œ„ํ•ด ํ™œ์„ฑํ™” ํ•ด์ฃผ๋„๋ก ํ•œ๋‹ค. ์ด ์˜ต์…˜๋“ค์€ TypeScript ๋ฅผ ํƒ€์ž…์— ๋Œ€ํ•ด ์—„๊ฒฉํ•œ ๋‹ค๋ฅธ ์–ธ์–ด๋“ค๊ณผ ์œ ์‚ฌํ•œ ํ™˜๊ฒฝ์„ ๋งŒ๋“ค์–ด์ค€๋‹ค.

4. Type Alias

interface์™€ ๋น„์Šทํ•˜์ง€๋งŒ ๋‹ค๋ฅธ ์–ธ์–ด์™€ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ๋งŒ๋“ค์–ด์ง„ ํƒ€์ž…์„ refer๋กœ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด์ง€ ์ง์ ‘ ํƒ€์ž…์„ ๋งŒ๋“œ๋Š” ๊ฒƒ์€ ์•„๋‹ˆ๋‹ค. interface๋ฅผ Type Alias๋กœ ๋Œ€์ฒดํ•˜๋Š” ๊ฒƒ์ด ๊ฐ€๋Šฅํ•œ ์ด์œ ๋Š” TypeScript ๊ฐ€ Object Literal ๊ทธ ์ž์ฒด๋ฅผ ํƒ€์ž…์œผ๋กœ ์ •์˜ํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

interface๋Š” ๋‹จ์ง€ Object ํ˜•ํƒœ๋งŒ ์ •์˜๊ฐ€ ๊ฐ€๋Šฅํ•˜์ง€๋งŒ, type์€ ๋” ์œ ์—ฐํ•˜๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. ์ฃผ๋กœ ๋ฐ˜๋ณต๋˜๋Š” ํƒ€์ž…์ด๋‚˜ Union Types ๋ฅผ ์ •์˜ํ•  ๋•Œ ์‚ฌ์šฉํ•œ๋‹ค.

๋ช…ํ™•ํžˆ ์ด์•ผ๊ธฐํ•˜๋ฉด interface์™€ type์€ ๋ฌธ๋ฒ•์ ์œผ๋กœ๋„ ๊ธฐ๋Šฅ์ ์œผ๋กœ๋„ ๋‹ค๋ฅด๋‹ค. ํ•˜์ง€๋งŒ ๋Œ€๋ถ€๋ถ„์˜ ๊ฒฝ์šฐ Object ํ˜•ํƒœ์˜ ํƒ€์ž…์„ ์ •์˜ํ•  ๋•Œ interface๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ๊ณผ type์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ ๋ชจ๋‘ ๊ฐ€๋Šฅํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์‹ค์ œ๋กœ ์ด ๋ถ€๋ถ„์— ์žˆ์–ด์„œ ์–ด๋–ค ๊ฒƒ์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ๋” ์ ์ ˆํ•œ๊ฐ€์— ๋Œ€ํ•œ ์˜๊ฒฌ์ด ๋‹ค์–‘ํ•˜๋‹ค.

์–ด์ฐจํ”ผ Structural Type System ์ด๊ธฐ ๋•Œ๋ฌธ์— ๋ฐ˜๋“œ์‹œ interface๋ฅผ ์จ์•ผ ํ•˜๊ฑฐ๋‚˜, type์„ ์จ์•ผํ•˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ์•„๋‹ˆ๋ผ๋ฉด ํ•ด๋‹น ์•ฑ์— ๋Œ€ํ•œ ์ฝ”๋”ฉ ์ปจ๋ฒค์…˜์„ ์ •์˜ํ•˜๊ณ  ์ด์— ๋”ฐ๋ฅด๋„๋ก ํ•˜๋ฉด ๋œ๋‹ค.


4. TypeScript Compiler ๐Ÿ‘ฉโ€๐Ÿ’ป

1. Compilation Context

TypeScript ์ฝ”๋“œ๋ฅผ ์–ด๋–ป๊ฒŒ JavaScript ์ฝ”๋“œ๋กœ ๋ณ€ํ™˜ํ• ๊ฑด์ง€๋ฅผ ์ •์˜ํ•˜๋Š” ๋ฐฉ๋ฒ•์œผ๋กœ tsconfig.json์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ๊ถŒ์žฅ๋˜๋ฉฐ, tsconfig ์˜ ์ตœ์ƒ์œ„ ํ”„๋กœํผํ‹ฐ๋Š” ํฌ๊ฒŒ 3๊ฐ€์ง€๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

  • compilerOptions: TypeScript ๋ฅผ JavaScript ๋กœ ๋ณ€ํ™˜ํ•˜๊ธฐ ์œ„ํ•ด ํ•„์š”ํ•œ ์„ธ๋ถ€ ์„ค์ •์„ ์ •์˜
  • include: JavaScript ๋กœ Transpile ํ•  ํŒŒ์ผ์˜ ๊ฒฝ๋กœ ๋ชฉ๋ก์„ ๋ฐฐ์—ด๋กœ ์ž‘์„ฑ
  • exclude: Transpile ์—์„œ ์ œ์™ธํ•  ํŒŒ์ผ์˜ ๊ฒฝ๋กœ ๋ชฉ๋ก์‡ ๋ฐฐ์—ด๋กœ ์ž‘์„ฑ
{
  "compilerOptions": {
    "lib": [
      "ESNext",
      "DOM"
    ],
    "module": "ESNext",
    "moduleResolution": "Node",
    "esModuleInterop": true,
    "forceConsistentCasingInFileNames": true,
    "strict": true,
    "skipLibCheck": true
  },
  "include": ["src/**/*.ts"],
  "exclude": ["node_modules"]
}

๋ฌผ๋ก  ์ด 3๊ฐœ ์™ธ์—๋„ ๋” ๋งŽ์€ ์ตœ์ƒ์œ„ ํ”„๋กœํผํ‹ฐ๊ฐ€ ์กด์žฌํ•˜๋Š” ๋ฐ ์œ„ 3๊ฐœ๊ฐ€ ๊ฐ€์žฅ ํ•ต์‹ฌ์ด๋ผ๊ณ  ํ•  ์ˆ˜ ์žˆ๋‹ค.

2. tsconfig schema

์œ„์—์„œ ์†Œ๊ฐœํ•œ compilerOptions, include, exclude ์™ธ์—๋„ TypeScript ์˜ ๋ฒ„์ „์ด ์˜ฌ๋ผ๊ฐ€๋ฉฐ ์ƒˆ๋กœ์šด ๊ธฐ๋Šฅ์ด ์ƒ๊ธฐ๊ฑฐ๋‚˜ ์„ธ๋ถ„ํ™” ๋˜๋ฉฐ ์ด ์Šคํ‚ค๋งˆ์˜ ํฌ๊ธฐ ์—ญ์‹œ ์ฆ๊ฐ€ํ•˜๊ณ ์žˆ๋‹ค. ๊ทธ ์ค‘ ์ค‘์š”ํ•œ ์ตœ์ƒ์œ„ ํ”„๋กœํผํ‹ฐ๋ฅผ ์ข€ ๋” ์ž์„ธํžˆ ์•Œ์•„๋ณด์ž.

  • compilerOptions
  • compileOnSave
  • extends
  • files / include / exclude
  • references

npx tsc --init์€ ๋งŽ์ด ์‚ฌ์šฉ๋˜๋Š” ์ผ๋ถ€๋งŒ ์ž‘์„ฑํ•ด์ฃผ๋Š” ๊ฒƒ์ด์ง€ ๋ชจ๋“  ๊ฒƒ์„ ์ž‘์„ฑํ•ด์ฃผ์ง€๋Š” ์•Š๋Š”๋‹ค. ๋ชจ๋“  ์˜ต์…˜๊ณผ ์„ค๋ช…์„ ๋ณด๋ ค๋ฉด TSConfig Reference ๋ฅผ ํ†ตํ•ด ํ™•์ธํ•˜๋„๋ก ํ•œ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ๋ ˆํผ๋Ÿฐ์Šค ํŽ˜์ด์ง€์— ๋ถ€์กฑํ•œ ๋ณด์ด ์„ค๋ช…์€ TypeScript - tsconfig ์— ์ž˜ ์ •๋ฆฌ๋˜์–ด ์žˆ์œผ๋‹ˆ ํ•จ๊ป˜ ์ฐธ๊ณ ํ•œ๋‹ค.

1. compileOnSave

{
  "compileOnSave": true
}

์ด ์˜ต์…˜์€ TypeScript ์ž์ฒด Config ์˜ต์…˜์ด ์•„๋‹ˆ๋‹ค. VS Code ์˜ Atom TypeScript ํ”Œ๋Ÿฌ๊ทธ์ธ์„ ์„ค์น˜ํ•ด์•ผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ์˜ต์…˜์œผ๋กœ Compile on save ๋ฅผ ์ฐธ๊ณ ํ•œ๋‹ค. ์ž๋™์œผ๋กœ ์ปดํŒŒ์ผ๊ณผ ์ €์žฅ์„ ์ˆ˜ํ–‰ํ•ด ๋ฌธ๋ฒ•์  ์—๋Ÿฌ๋ฅผ ๋ฐœ๊ฒฌํ•˜๊ธฐ ์‰ฝ๋„๋ก ํ•ด์ค€๋‹ค.

๋งŒ์•ฝ JetBrains ๊ณ„์—ด์˜ IDE ๋ฅผ ์‚ฌ์šฉํ•  ๊ฒฝ์šฐ ์œ„ ํ”„๋กœํผํ‹ฐ ์„ค์ • ์—†์ด IDE ๊ฐ€ ๊ธฐ๋ณธ์œผ๋กœ ์ง€์›ํ•œ๋‹ค.

2. extends

TypeScript ์ž์ฒด Config ์˜ต์…˜์ด์ง€๋งŒ ๊ธฐ๋ณธ๊ฐ’์€ ์•„๋‹ˆ๋ผ ํ•„์š”ํ•  ๊ฒฝ์šฐ ์ž‘์„ฑํ•ด์„œ ์‚ฌ์šฉํ•ด์•ผํ•œ๋‹ค. ์ด๊ฒƒ์€ JSON ํŒŒ์ผ์„ ์—ฌ๋Ÿฌ ๊ฐœ๋กœ ๋‚˜๋ˆ„์–ด ํ™•์žฅ์„ ํ†ตํ•ด ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•ด์ฃผ๋Š” ์˜ต์…˜์ด๋‹ค.

  • base.json
{
  "compilerOptions": {
    "strict": true,
    "noImplicitAny": true,
    "strictNullChecks": true,
    "strictFunctionTypes": true
  }
}

  • tsconfig.json
{
  "extends": "./base",
  "compilerOptions": {
    // ...
  }
}

์ด๋ ‡๊ฒŒ ์‚ฌ์šฉํ•˜๋ฉด tsconfig.json์€ base.json์˜ ๋‚ด์šฉ์„ ํ™•์žฅ์„ ํ†ตํ•ด ๊ฐ–๊ฒŒ ๋œ๋‹ค. tsconfig / bases ์— ๊ฐ€๋ฉด ์—ฌ๋Ÿฌ ๊ฐœ๋ฐœ ํ™˜๊ฒฝ๋ณ„๋กœ ๋งž์ถ˜ ๊ธฐ๋ณธ์œผ๋กœ ์‚ฌ์šฉํ•˜๋ฉด ์ข‹์€ tsconfig ์„ค์ •์„ ์ œ๊ณตํ•œ๋‹ค. ๋‹ค์Œ์€ CRA ์„ ์‚ฌ์šฉํ•  ๊ฒฝ์šฐ์˜ ์˜ˆ์‹œ๋‹ค.

npm install --save-dev @tsconfig/create-react-app
yarn add --dev @tsconfig/create-react-app
{
  "extends": "@tsconfig/bun/tsconfig.json"
}

3. files, include, exclude

files

{
  "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"
  ]
}

์™€ ๊ฐ™์ด ๋ฆฌ์ŠคํŠธ ๋ฐฐ์—ด๋กœ ์ž‘์„ฑํ•œ๋‹ค. ์ƒ๋Œ€ ๊ฒฝ๋กœ์™€ ์ ˆ๋Œ€ ๊ฒฝ๋กœ๋ฅผ ๋ชจ๋‘ ์ง€์›ํ•˜๋ฉฐ ๊ฐœ๋ณ„ ํŒŒ์ผ ๋ชฉ๋ก์„ ์ „๋ถ€ ์ž…๋ ฅํ•ด์ค˜์•ผํ•œ๋‹ค. ์ด๊ฒƒ์€ ํŒŒ์ผ์˜ ๊ฐœ์ˆ˜๊ฐ€ ์ ๊ณ , ์ปดํŒŒ์ผ ํ•˜๊ณ ์ž ํ•˜๋Š” ํŒŒ์ผ์„ ์ง€์ •ํ•ด์•ผํ•  ๋•Œ ์œ ์šฉํ•˜๋‹ค.


include & exclude

{
  "include": [
      "src/**/*.ts"
  ],
  "exclude": [
      "node_modules",
      "**/*.spec.ts"
  ]
}

๊ผญ ํ•จ๊ป˜ ์‚ฌ์šฉํ•  ํ•„์š”๋Š” ์—†์œผ๋‚˜ ์ผ๋ฐ˜์ ์œผ๋กœ ์œ„์™€ ๊ฐ™์€ ํ˜•ํƒœ๋กœ ํ•จ๊ป˜ ์‚ฌ์šฉํ•œ๋‹ค. .gitignore ํŒŒ์ผ์ฒ˜๋Ÿผ glob ํŒจํ„ด์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์–ด, ํŠน์ • ๊ฒฝ๋กœ๋‚˜ ํŒจํ„ด์— ๋Œ€ํ•ด ์ „๋ถ€ include, exclude๋ฅผ ์ ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.


์šฐ์„ ์ˆœ์œ„

  1. ์•„๋ฌด๋Ÿฐ ์„ค์ •์„ ํ•˜์ง€ ์•Š์œผ๋ฉด ๊ธฐ๋ณธ์ ์œผ๋กœ node_modules, bower_components, jspm_packages, <outDir> 4๊ฐœ๋ฅผ ์ œ์™ธํ•˜๊ณ  ๋ชจ๋‘ ์ปดํŒŒ์ผํ•œ๋‹ค.
  2. exclude ์„ค์ •์„ ํ•˜๋ฉด ์ด๊ฒƒ์„ ์ œ์™ธํ•˜๊ณ  ๋ชจ๋‘ ์ปดํŒŒ์ผํ•œ๋‹ค. 1๋ฒˆ์˜ ๊ธฐ๋ณธ ์ œ์™ธ ํ•ญ๋ชฉ์€ ๋ณ„๋„๋กœ ์ง€์ •ํ•ด์ฃผ์ง€ ์•Š์•„๋„ ๊ธฐ๋ณธ์ ์œผ๋กœ ์ œ์™ธ๋˜๊ธฐ ๋•Œ๋ฌธ์— ์œ„ ๊ฒฝ๋กœ ์™ธ ์ถ”๊ฐ€๋กœ ์ œ์™ธํ•  ํŒŒ์ผ ๋˜๋Š” ๊ฒฝ๋กœ๋งŒ ๋ชฉ๋ก์— ์ž‘์„ฑํ•˜๋ฉด ๋œ๋‹ค.
  3. include ์„ค์ •์„ ํ•˜๋ฉด ์ด๊ฒƒ๋งŒ ์ปดํŒŒ์ผํ•œ๋‹ค. ๋‹จ, <outDir>์€ ํฌํ•จ์‹œํ‚ค๋”๋ผ๋„ ๊ฐ•์ œ๋กœ ์ œ์™ธ๋œ๋‹ค.
  4. ์šฐ์„ ์ˆœ์œ„๋Š” files > exclude > include ์ด๋‹ค. files์— ์กด์žฌํ•˜๋ฉด, exclude์— ํฌํ•จ๋˜์–ด ์žˆ๋”๋ผ๋„ ์ปดํŒŒ์ผ๋˜๋ฉฐ, include์— ํฌํ•จ๋˜์–ด ์žˆ๋”๋ผ๋„ exclude์— ํฌํ•จ๋˜๋ฉด ์ปดํŒŒ์ผ์—์„œ ์ œ์™ธ๋œ๋‹ค.

4. references

{
  "references": [
    { "path": "./path/to/project1" },
    { "path": "./path/to/project2" }
  ]
}

package.json์ด ์™ธ๋ถ€ ํŒจํ‚ค์ง€์˜ ์˜์กด์„ฑ์„ ์„ค์ •ํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ๋œ๋‹ค๋ฉด, tsconfig.json์€ TypeScript ํ”„๋กœ์ ํŠธ ๊ฐ„ ์˜์กด์„ฑ๊ณผ ๋นŒ๋“œ ์ˆœ์„œ๋ฅผ ์„ค์ •ํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ๋œ๋‹ค. ์—ฌ๋Ÿฌ ํ”„๋กœ์ ํŠธ๋ฅผ ๋ชจ์•„ ํ•˜๋‚˜์˜ ํ”„๋กœ์ ํŠธ๋กœ ๊ตฌํ˜„ํ•  ๊ฒฝ์šฐ ์ด ์„ค์ •์„ ์ง€์ •ํ•˜๋ฉด ์ปดํŒŒ์ผ๋Ÿฌ๊ฐ€ ๋ณ€๊ฒฝ๋œ ํ”„๋กœ์ ํŠธ๋งŒ ์žฌ์ปดํŒŒ์ผ ํ•ด ๋นŒ๋“œ ์‹œ๊ฐ„์„ ์ตœ์ ํ™” ํ•  ์ˆ˜ ์žˆ๋‹ค.

5. compilerOptions

compilerOptions ๋Š” TypeScript ์ปดํŒŒ์ผ์— ๊ด€๋ จ๋œ ์„ค์ •์„ ๋‹ค๋ฃจ๊ธฐ ๋•Œ๋ฌธ์— ๊ฐ€์žฅ ๋งŽ์€ ํ”„๋กœํผํ‹ฐ๊ฐ€ ์กด์žฌํ•œ๋‹ค. ๋”ฐ๋ผ์„œ ๋ฐ”๋กœ ์•„๋ž˜ compilerOptions ์—์„œ ๋ณ„๋„๋กœ ๋‹ค๋ฃจ๋„๋ก ํ•œ๋‹ค.

3. tsconfig schema - compilerOptions

1. target / lib

target

{
  "compilerOptions": {
    "target": "ES5"
  }
}

JavaScript ๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ๋Š” ๋ฐฐํฌ๋ฅผ ํ•˜๊ธฐ ์ „ ES ๋ ˆ๋ฒจ์„ ์–ด๋””๊นŒ์ง€ ๋‚ด๋ ค ๋ฐฐํฌํ• ์ง€ babel ๊ฐ™์€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•ด ๋ณ€ํ™˜, ๋ฐฐํฌํ–ˆ์—ˆ๋‹ค. ํ•˜์ง€๋งŒ TypeScript ๋Š” ํ•ญ์ƒ ๋ฐฐํฌ ์ „ JavaScript ๋กœ ๋ณ€ํ™˜ํ•ด์•ผํ•˜๊ธฐ ๋•Œ๋ฌธ์— babel๊ณผ ๊ฐ™์€ ๋ณ„๋„์˜ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์—†์ด ์ง์ ‘ ๋ณ€ํ™˜ํ•  ํƒ€๊ฒŸ์„ ์„ค์ •ํ•˜๊ณ  ์ปดํŒŒ์ผํ•œ๋‹ค. ์ด๊ฒƒ์„ ์„ค์ •ํ•˜๋Š” ๊ฒƒ์ด ๋ฐ”๋กœ target ์˜ต์…˜์ด๋‹ค.

  • ES3
  • ES5
  • ES6 / ES2015
  • ES2016
  • โ€ฆ
  • ES2022
  • ESNext

๋ฅผ ์„ค์ •ํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ESNext๋Š” latest, last ์™€ ๊ฐ™์€ ์˜๋ฏธ๋กœ ์‚ฌ์šฉ๋œ๋‹ค. ํ•ญ์ƒ ์ตœ์‹  ๋ฒ„์ „์„ ํƒ€๊ฒŸ์œผ๋กœ ํ•œ๋‹ค. ๋ณดํ†ต Node ์„œ๋ฒ„์—์„œ๋Š” ํ•„์š”์— ๋”ฐ๋ผ ๋ฒ„์ „์„ ์˜ฌ๋ฆฌ์ง€๋งŒ ํ”„๋ก ํŠธ์—”๋“œ๋Š” ๋ธŒ๋ผ์šฐ์ € ํ˜ธํ™˜์„ฑ ๋ฌธ์ œ๋กœ โ€œES2015โ€(=ES6)๋ฅผ ํ‘œ์ค€์œผ๋กœ ์‚ฌ์šฉํ•œ๋‹ค.


lib

{
  "compilerOptions": {
    "lib": ["ESNext", "DOM"]
  }
}

์ปดํŒŒ์ผ๋Ÿฌ๊ฐ€ ์‚ฌ์šฉํ•  ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์ง€์ •ํ•˜๋Š” ๊ฒƒ์œผ๋กœ ๋Œ€๋ถ€๋ถ„ target์— ๋”ฐ๋ผ default ๋กœ ์„ค์ •๋˜๋Š” lib๊ฐ€ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์ง์ ‘ ์„ค์ •ํ•  ํ•„์š”๋Š” ๊ฑฐ์˜ ์—†๋‹ค.

  • ES3: lib.d.ts
  • ES5: dom, es5, scripthost
  • ES6: dom, es6, dom.iterable, scripthost

๋ฅผ ๊ธฐ๋ณธ์œผ๋กœ ์‚ฌ์šฉํ•œ๋‹ค. ์ง์ ‘ ์„ค์ •์‹œ ํ”„๋ก ํŠธ์—”๋“œ์—์„œ๋Š” ์ ˆ๋Œ€ DOM์ด ๋ˆ„๋ฝ๋˜์–ด์„œ๋Š” ์•ˆ ๋œ๋‹ค.

2. module

{
  "compilerOptions": {
    "module": "ESNext"
  }
}

๋ชจ๋“ˆ ์‹œ์Šคํ…œ์„ ์ง€์ •ํ•œ๋‹ค. โ€œCommonJSโ€, โ€œAMDโ€, โ€œES5โ€, โ€œESNextโ€, โ€œNodeโ€, โ€œNodeNextโ€, โ€œSystemโ€ ๋“ฑ์„ ์ง€์ •ํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ ํ”„๋ก ํŠธ์—”๋“œ๋Š” ๋ณดํ†ต ESNext๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.

3. moduleResolution

{
  "compilerOptions": {
    "moduleResolution": "Node"
  }
}

๋ชจ๋“ˆ ํ•ด์„ ๋ฐฉ์‹์„ ์ง€์ •ํ•œ๋‹ค. ์ผ๋ฐ˜์ ์œผ๋กœ โ€œNodeโ€ ์™€ โ€œClassicโ€ ์ค‘์—์„œ ์„ ํƒ์„ ํ•˜๊ฒŒ ๋˜๋Š”๋ฐ, โ€œClassicโ€ ์„ ์„ ํƒํ•˜๋ฉด ํŒŒ์ผ ๊ฒฝ๋กœ์—์„œ .ts๊นŒ์ง€ ์ „๋ถ€ ์ž…๋ ฅํ•ด์ฃผ์–ด์•ผํ•œ๋‹ค. Node๋ฅผ ์„ค์ •ํ•ด์•ผ index.ts ์™€ .ts๋ฅผ ์ƒ๋žตํ•  ์ˆ˜ ์žˆ๋‹ค.

4. esModuleInterop

{
  "compilerOptions": {
    "esModuleInterop": true
  }
}

ESM ๋ชจ๋“ˆ ๋ฐฉ์‹ ํ˜ธํ™˜์„ฑ์„ ํ™œ์„ฑํ™”ํ•œ๋‹ค. CommonJS ๋ฐฉ์‹์˜ export ์—๋Š” default ๋‚ด๋ณด๋‚ด๊ธฐ๊ฐ€ ์—†๋‹ค. CommonJS ์™€ ESM ๋ฐฉ์‹์˜ import, export Syntax ๊ฐ€ ์กฐ๊ธˆ์”ฉ ๋‹ค๋ฅธ๋ฐ, ์ด๋ฅผ ๊ตฌ๋ถ„ํ•˜์ง€ ์•Š๊ณ  ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ํ˜ธํ™˜์„ฑ์„ ๋ณด์žฅํ•ด์ฃผ๋Š” ์„ค์ •์ด๋‹ค.

5. isolateModules

{
  "compilerOptions": {
    "isolatedModules": true
  }
}

๋ชจ๋“  ํŒŒ์ผ์„ ๋ชจ๋“ˆ๋กœ ์ปดํŒŒ์ผํ•œ๋‹ค. ์ด ์„ค์ •์„ true๋กœ ํ•  ๊ฒฝ์šฐ ๋ชจ๋“  ํŒŒ์ผ์€ import ๋˜๋Š” export๋ฅผ ํ•˜๋‚˜ ์ด์ƒ ํฌํ•จํ•ด ๋ชจ๋“ˆ์ด ๋˜๋„๋ก ๊ฐ•์ œ๋œ๋‹ค. ๋งŒ์•ฝ ์ด ์„ค์ •์„ ํ™œ์„ฑํ™” ํ–ˆ์„ ๊ฒฝ์šฐ import/export ๊ฐ€ ํ•„์š”ํ•˜์ง€ ์•Š๋‹ค๋ฉด export {}๋ฅผ ์ ์–ด์ฃผ์–ด์•ผ ๋ชจ๋“ˆ๋กœ ์ธ์‹ํ•ด ์ปดํŒŒ์ผ ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•˜์ง€ ์•Š๋Š”๋‹ค.

6. baseUrl / paths

baseUrl

๋ชจ๋“ˆ ํ•ด์„์— ์‚ฌ์šฉํ•  ๊ธฐ์ค€ ๊ฒฝ๋กœ๋ฅผ ์ง€์ •ํ•œ๋‹ค. ์‰ฝ๊ฒŒ ๋งํ•˜๋ฉด import์— ์‚ฌ์šฉํ•  ๊ธฐ๋ณธ ๊ฒฝ๋กœ๋ฅผ ์ง€์ •ํ•˜๋Š” ๊ฒƒ์ด๋‹ค.

๋‹ค์Œ ์˜ˆ์ œ๋Š” /src/pages/members/Vip.ts ํŒŒ์ผ์—์„œ ์™ธ๋ถ€ ๋ชจ๋“ˆ์„ ๊ฐ€์ ธ์˜จ๋‹ค.

Project src

import styled from 'styled-components';
import Input from '../../components/Input';
import Button from '../../components/Button';
import Info from '../../components/user/Info';
import { isAdult } from '../../utils/calendar';

node_modules๋Š” ๋ณ„๋„์˜ ๊ฒฝ๋กœ๋ฅผ ์ž‘์„ฑํ•˜์ง€ ์•Š์•„๋„ ๋˜์ง€๋งŒ ์‚ฌ์šฉ์ž๊ฐ€ ์ƒ์„ฑํ•œ ๋ชจ๋“ˆ์€ ์œ„์™€ ๊ฐ™์ด ์ƒ์„ธํ•œ ๊ฒฝ๋กœ๋ฅผ ์ž‘์„ฑํ•ด์•ผํ•œ๋‹ค. ์ด๋•Œ ํ”„๋กœ์ ํŠธ๊ฐ€ ์ปค์ง€๊ณ  ๊ฒฝ๋กœ๊ฐ€ ๋ณต์žกํ•ด์ง€๋ฉด ์ƒ๋‹นํžˆ ํ˜ผ๋ž€์Šค๋Ÿฌ์›Œ์ง„๋‹ค. ์ด๋•Œ tsconfig.json์„ ๊ธฐ์ค€์œผ๋กœ ์‚ฌ์šฉํ•˜๊ณ ์ž ํ•˜๋Š” ๊ธฐ๋ณธ ๋””๋ ‰ํ† ๋ฆฌ ์œ„์น˜๋ฅผ baseUrl์— ์ž‘์„ฑํ•˜๋ฉด import ์‹œ ๋ชจ๋“ˆ์˜ ์ƒ๋Œ€๊ฒฝ๋กœ ๋ฟ ์•„๋‹ˆ๋ผ ์ ˆ๋Œ€๊ฒฝ๋กœ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค(๋ฌผ๋ก , ์ƒ๋Œ€๊ฒฝ๋กœ๋„ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•˜๋‹ค).

{
  "compilerOptions": {
    "baseUrl": "src"
  }
}
import styled from 'styled-components';
import Input from 'components/Input';
import Button from 'components/Button';
import Info from 'components/user/Info';
import { isAdult } from 'utils/calendar';


paths

์‰ฝ๊ฒŒ ๋งํ•ด alias๋‹ค. baseUrl์ด ๋ชจ๋“ˆ ํ•ด์„์— ์‚ฌ์šฉํ•  ๊ธฐ์ค€ ๊ฒฝ๋กœ๋งŒ ์ง€์ •ํ•œ๋‹ค๋ฉด, paths๋Š” ์ข€ ๋” ์„ธ๋ถ„ํ™” ์‹œํ‚ค๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉํ•œ๋‹ค. path ๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ baseUrl ์— ์˜ํ–ฅ์„ ๋ฐ›์œผ๋ฏ€๋กœ, baseUrl ์„ ์„ค์ •ํ–ˆ์„ ๊ฒฝ์šฐ, ํ•ด๋‹น ๊ฒฝ๋กœ๋ฅผ ์ƒ๋žตํ•˜๊ณ  ์‹œ์ž‘ํ•  ์ˆ˜ ์žˆ๋‹ค. ์œ„ ๊ฒฝ์šฐ src/components ๋Œ€์‹  components๋งŒ ์ž‘์„ฑํ•ด๋„ ๋œ๋‹ค๋Š” ๋ง์ด๋‹ค.

{
  "compilerOptions": {
    "baseUrl": "src",
    "paths": {
      "@components/*": ["components/*", "components/user/*"],
      "@utils/*": ["utils/*"]
    },
  }
}
import styled from 'styled-components';
import Input from '@components/Input';
import Button from '@components/Button';
import Info from '@components/Info';
import { isAdult } from '@utils/calendar';

๋˜๋Š” depth 1 ์˜ ๊ฒฝ๋กœ๋งŒ ์ž๋™์œผ๋กœ ๋“ฑ๋ก์‹œํ‚ค๋ ค๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

{
  "compilerOptions": {
    "baseUrl": "src",
    "paths": {
      "@*": ["*"]
    },
  }
}
import styled from 'styled-components';
import Input from '@components/Input';
import Button from '@components/Button';
import Info from '@components/user/Info';
import { isAdult } from '@utils/calendar';

์ด ๊ฒฝ์šฐ import Info from '@components/user/Info';๋Š” import Info from '@components/Info';๋กœ ์ถ•์•ฝํ•  ์ˆ˜ ์—†์Œ์— ์œ ์˜ํ•œ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ๊ฐœ์ธ์ ์œผ๋กœ ์ด ๋ฐฉ๋ฒ•์€ ๊ถŒ์žฅํ•˜์ง€ ์•Š๋Š”๋‹ค. *๋ฅผ ์‚ฌ์šฉํ•˜๋‹ค๋ณด๋‹ˆ path ์˜ root ์— ์žˆ๋Š” ํŒŒ์ผ์„ ๊ฐ€์ ธ์˜ฌ ๊ฒฝ์šฐ ๊ฐ„ํ˜น ์ œ๋Œ€๋กœ ๋งคํ•‘์ด ๋˜์ง€ ์•Š๊ธฐ๋„ ํ•˜๊ณ  style ๊ฐ™์€ ๋””๋ ‰ํ† ๋ฆฌ๋Š” ๊ณ„์† ์—๋Ÿฌ ๋งคํ•‘์ด ๋˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ๊ฐ„ํ˜น ๋ฐœ์ƒํ•œ๋‹ค. ๋˜ํ•œ ๊ฐœ๋ณ„ ๋“ฑ๋กํ•  ๊ฒฝ์šฐ

import Input from '../../components/Input';
import Input from 'components/Input';
import Input from '@components/Input';

์ด 3๊ฐ€์ง€ ๋ฐฉ๋ฒ• ์ค‘ ์–ด๋–ค ๊ฒƒ์„ ์‚ฌ์šฉํ•ด๋„ ์ž‘๋™ํ•˜์ง€๋งŒ, *๋กœ path ๋ฅผ ์ง€์ •ํ•˜๋Š” ๊ฒฝ์šฐ @์„ ์‚ฌ์šฉํ•œ ์ ‘๊ทผ ์™ธ ์ฒซ ๋ฒˆ์งธ ์ƒ๋Œ€ ๊ฒฝ๋กœ๋‚˜ ๋‘ ๋ฒˆ์งธ ์ ˆ๋Œ€๊ฒฝ๋กœ๋ฅผ ํ†ตํ•œ ์ ‘๊ทผ์€ ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค.

๋˜ํ•œ tsconfig ์œ„์น˜๋กœ๋ถ€ํ„ฐ ๋‹ค๋ฅธ ๋””๋ ‰ํ† ๋ฆฌ๋กœ ๋ถ„๋ฅ˜๋˜๋Š” ๊ฒฝ์šฐ ๋‹ค๋ฅธ ๋ชจ๋“ˆ๋กœ ๋ถ„๋ฆฌํ•˜๋Š” ๊ฒƒ์œผ๋กœ ๋ณด์ธ๋‹ค.
/api/...์™€ /src/... ๋‘ ๋””๋ ‰ํ† ๋ฆฌ๊ฐ€ ์žˆ์„ ๋•Œ "baseUrl": ".", "paths": { "@utils/*": ["src/utils/*"] }๋ฅผ ์„ค์ •ํ–ˆ์Œ์—๋„ /api/... ํ•˜์œ„ ๋ชจ๋“ˆ์—์„œ๋Š” @utils/calendar๋Š” ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค. ์ƒ๋Œ€๊ฒฝ๋กœ๋กœ ../src/utils/calendar๋กœ ์ˆ˜์ •ํ•ด์•ผ ์ •์ƒ์ ์œผ๋กœ ์ž‘๋™ํ•œ๋‹ค. ์ด ๋ถ€๋ถ„์— ๋Œ€ํ•ด์„œ๋Š” ๋‹ค์Œ commit log ๋ฅผ ์ฐธ๊ณ ํ•˜๋„๋ก ํ•œ๋‹ค.

7. rootDirs / outDir / outFile

rootDirs, outDir, outFile์€ ๋ชจ๋‘ files, include, exclude ์™€ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ baseUrl์— ์˜ํ–ฅ์„ ๋ฐ›์ง€ ์•Š๋Š”๋‹ค. ์ด๊ฒƒ๋“ค์€ ๋ชจ๋‘ ์ปดํŒŒ์ผํ•  ๋Œ€์ƒ์„ ์„ค์ •ํ•˜๋Š” ํ”„๋กœํผํ‹ฐ๋กœ tsconfig.json์„ ๊ธฐ์ค€์œผ๋กœ ์ง€์ •ํ•œ๋‹ค.

rootDirs / outDir

{
  "compilerOptions": {
    "rootDirs": ["src"],
    "outDir": "dist"
  }
}

์ปดํŒŒ์ผ ํ•  root ๋””๋ ‰ํ† ๋ฆฌ์™€ ๊ทธ๊ฒƒ์„ ์ถœ๋ ฅํ•  ๋ชฉํ‘œ ๋””๋ ‰ํ† ๋ฆฌ๋ฅผ ์ง€์ •ํ•œ๋‹ค. outDir์€ ์ผ๋ฐ˜์ ์œผ๋กœ โ€œdistโ€, โ€œpublicโ€, โ€œoutโ€๊ณผ ๊ฐ™์€ ๊ฒฝ๋กœ๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.

rootDirs์€ files, include, exclude ์˜ ์˜ํ–ฅ์„ ๋ฐ›๋Š”๋‹ค. ๋”ฐ๋ผ์„œ

{
  "include": [
      "src/**/*.ts"
  ],
  "exclude": [
      "node_modules",
      "**/*.spec.ts"
  ]
}

๋Š” include, exclude์™€ ํ•จ๊ป˜ ์‚ฌ์šฉํ•  ๊ฒฝ์šฐ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค.

{
  "compilerOptions": {
    "rootDirs": ["src"],
    "outDir": "dist"
  },
  "include": [
      "**/*.ts"
  ],
  "exclude": [
      "node_modules",
      "**/*.spec.ts"
  ]
}

rootDirs๋กœ ์ปดํŒŒ์ผ์„ ํ•  root ๋””๋ ‰ํ† ๋ฆฌ๊ฐ€ src๋กœ ์ง€์ •๋˜์—ˆ๊ธฐ ๋•Œ๋ฌธ์— include์˜ ํŒจํ„ด์€ src ๊ฒฝ๋กœ๋ฅผ ํฌํ•จํ•  ํ•„์š”๊ฐ€ ์—†๋‹ค.


outFile

{
  "compilerOptions": {
    "outFile": "dist/main.js"
  }
}

module์ด AMD ๋˜๋Š” System ๊ฐ™์€ ํ˜•ํƒœ์ผ ๋•Œ ๋ชจ๋“  JavaScript ์ฝ”๋“œ๋ฅผ ๋‹จ์ผ ํŒŒ์ผ๋กœ ์ปดํŒŒ์ผํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•˜๋Š” ์˜ต์…˜์œผ๋กœ ์ผ๋ฐ˜์ ์œผ๋กœ CommonJS, ES6 ๊ฐ™์€ ํ˜•ํƒœ๋กœ ์‚ฌ์šฉํ•  ๋•Œ๋Š” ์‚ฌ์šฉ์ด ๋ถˆ๊ฐ€๋Šฅํ•˜๋‹ค.

8. typeRoots / types

typeRoots

{
  "compilerOptions": {
    "typeRoots": [
      "node_modules/@types",
      "utils/types",
      "vendor/types"
    ]
  }
}

JavaScript ๋กœ ์ž‘์„ฑ๋œ ๋ชจ๋“ˆ์— ๋Œ€ํ•ด ์ปดํŒŒ์ผ๋Ÿฌ๊ฐ€ ์ฐธ์กฐํ•  ํƒ€์ž… ์„ ์–ธ d.ts ๊ฒฝ๋กœ๋ฅผ ์ง€์ •ํ•œ๋‹ค. node_modules/@types ๋””๋ ‰ํ† ๋ฆฌ๋Š” ํŠน๋ณ„ํ•œ ๊ฒฝ๋กœ๋กœ ๋ฏธ์ง€์ •์‹œ ๊ธฐ๋ณธ๊ฐ’์œผ๋กœ ์‚ฌ์šฉ๋œ๋‹ค. ํ•˜์ง€๋งŒ ์ด ๊ทœ์น™์„ ๋”ฐ๋ฅด์ง€ ์•Š๋Š” JavaScript ๊ธฐ๋ฐ˜ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋‚˜ ์œ ํ‹ธ์„ ์œ„ํ•ด d.ts ํŒŒ์ผ์„ ์ œ๊ณตํ•ด์•ผ ํ•  ๊ฒฝ์šฐ ์ด ํ”„๋กœํผํ‹ฐ์— ๋ฐฐ์—ด๋กœ ์ง€์ •ํ•œ๋‹ค. ์ด๋•Œ ์ฃผ์˜ํ•ด์•ผ ํ•  ๊ฒƒ์ด node_modules/@types๋ฅผ ์ œ์™ธํ•˜๊ณ  ๋ฐฐ์—ด์„ ์ž‘์„ฑํ•˜๋ฉด typeRoots ๊ฐ’์ด ์ œ๊ณต๋˜์—ˆ๊ธฐ ๋•Œ๋ฌธ์— ๊ธฐ๋ณธ๊ฐ’์ด ์‚ฌ์šฉ๋˜์ง€ ์•Š์œผ๋ฏ€๋กœ ํฌํ•จ์‹œ์ผœ์ฃผ์–ด์•ผํ•œ๋‹ค.


types

JavaScript ๋ชจ๋“ˆ์„ ์‚ฌ์šฉํ•  ๋•Œ typeRoots์—์„œ d.ts๋ฅผ ๊ฒ€์ƒ‰ํ•  ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ๊ฐœ๋ณ„๋กœ ์ง€์ •ํ•œ๋‹ค. ๋ฏธ์ง€์ •์‹œ ๋ชจ๋“  JavaScript ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์— ๋Œ€ํ•ด d.ts๋ฅผ ๊ฒ€์ƒ‰ํ•œ๋‹ค.

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

์œ„์™€ ๊ฐ™์ด ์ง€์ •ํ•  ๊ฒฝ์šฐ node, lodash, express 3๊ฐœ์˜ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์— ๋Œ€ํ•ด์„œ๋งŒ d.ts๋ฅผ ๊ฒ€์ƒ‰ํ•œ๋‹ค. ๋งŒ์•ฝ types๋ฅผ ๋ฏธ์ง€์ •ํ•˜์ง€ ์•Š๊ณ  "types": []์™€ ๊ฐ™์ด ๋นˆ ๋ฐฐ์—ด๋กœ ์ง€์ •ํ•  ๊ฒฝ์šฐ d.ts๋ฅผ ๊ฒ€์ƒ‰ํ•˜๋Š” ํƒ€์ž… ์‹œ์Šคํ…œ์„ ์ด์šฉํ•˜์ง€ ์•Š๊ฒ ๋‹ค๋Š” ์˜๋ฏธ๊ฐ€ ๋œ๋‹ค.

ํŠน๋ณ„ํ•œ ๊ฒฝ์šฐ๊ฐ€ ์•„๋‹ˆ๋ผ๋ฉด ์ด ํ”„๋กœํผํ‹ฐ๋Š” ๋ฏธ์ง€์ • ์ƒํƒœ๋กœ ๋‘๋Š” ๊ฒƒ์ด ์ข‹๋‹ค.

TypeScript ์—์„œ ์ด๋ฏธ์ง€๋ฅผ import ๊ตฌ๋ฌธ์ด ์ œ๋Œ€๋กœ ์ธ์‹ํ•˜์ง€ ๋ชปํ•˜๋Š” ๋ฌธ์ œ๊ฐ€ ์žˆ๋‹ค. ์ด๊ฒƒ์€ root ๊ฒฝ๋กœ์— d.tsํŒŒ์ผ์„ ๋งŒ๋“ค์–ด declare๋ฅผ ํ†ตํ•ด ์ด๋ฏธ์ง€๋ฅผ ๋ชจ๋“ˆ๋กœ ์ •์˜ํ•ด์ฃผ๋ฉด ๋œ๋‹ค.

  • images.d.ts
declare module "*.jpg";
declare module "*.jpeg";
declare module "*.png";
declare module "*.gif";
declare module "*.webp";

typeRoots, types๋ฅผ ๋ฏธ์ง€์ • ์ƒํƒœ๋กœ ๋‘˜ ๊ฒฝ์šฐ root ๊ฒฝ๋กœ์— ์ƒ์„ฑํ•œ images.d.ts๋ฅผ ์ž๋™์œผ๋กœ ์ธ์‹ํ•˜๋ฏ€๋กœ ๋”ฐ๋กœ ์ˆ˜์ •ํ•ด์ค„ ํ•„์š”๋Š” ์—†๋‹ค.

9. strict

{
  "compilerOptions": {
    "strict": true
  }
}

strict๋Š” ๋ฐ˜๋“œ์‹œ true๋กœ ์„ค์ •ํ•˜๋Š” ๊ฒƒ์„ ๊ธฐ๋ณธ์œผ๋กœ ํ•œ๋‹ค. ์ด๊ฒƒ์„ ํ™œ์„ฑํ™” ํ•˜๋ฉด ์ปดํŒŒ์ผ ๋œ JavaScript ํŒŒ์ผ ์ƒ๋‹จ์— "use strict";๊ฐ€ ํฌํ•จ๋  ๊ฒƒ์ด๋‹ค. ์ด ์˜ต์…˜์€ ์œ„ Type System ์—์„œ ์‚ดํŽด๋ณด์•˜๋˜,

  • noImplicitAny
  • noImplicitThis
  • strictNullChecks
  • strictFunctionTypes
  • strictPropertyInitialization
  • strictBindCallApply
  • alwaysStrict

TypeScript ๊ฐ€ ์ข€ ๋” Type-Safe ํ•œ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๋„๋ก ๋•๋Š” ๋Œ€๋ถ€๋ถ„์˜ ์˜ต์…˜์„ ์ผœ๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•œ๋‹ค(์ผ๋ถ€ ํ™œ์„ฑํ™” ๋˜์ง€ ์•Š๋Š” ์˜ˆ์™ธ ์กด์žฌ).


1 ) noImplicitAny

function noImplicitAny(x) {
  return x;
}

๋ช…์‹œ์ ์ธ any๋Š” ํ—ˆ์šฉ๋˜์ง€๋งŒ, ํƒ€์ž… ์ถ”๋ก ์— ์˜ํ•œ any๋Š” ํ—ˆ์šฉํ•˜์ง€ ์•Š๋Š”๋‹ค(๊ทธ๋ ‡๋‹ค๊ณ  ์‚ฌ์šฉํ•˜๋ผ๋Š” ๊ฒƒ์€ ์•„๋‹ˆ๋‹ค ํ•„์š”์‹œ unknown ์„ ์‚ฌ์šฉํ•  ๊ฒƒ).

function noImplicitAny(x: any) {
  return x;
}


2 ) noImplicitThis

function greet(age: number) {
  console.log(`Hello, ${this.name}! I'm ${age} years old`);
}

์ด๋Ÿฐ์‹์˜ this๊ฐ€ ์—†๋Š” ํ˜•ํƒœ๋Š” ์—๋Ÿฌ๋กœ ๊ฐ„์ฃผ๋œ๋‹ค. JavaScript ์˜ this๋Š” ์›Œ๋‚™ ์‹ฌ์˜คํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋ณ€ํ™˜์‹œ ์ž˜๋ชป๋œ this๋ฅผ ์‚ฌ์šฉํ•˜๊ฒŒ ๋˜๋Š” ๊ฒƒ์„ ๋ง‰๊ธฐ ์œ„ํ•ด ๋ช…์‹œ์ ์œผ๋กœ ์ •ํ™•ํ•œ ์ •๋ณด์˜ this๋ฅผ ์ œ๊ณตํ•ด์•ผํ•œ๋‹ค.

์ด๊ฒƒ์€ Python ์˜ ๋ฌธ๋ฒ•๊ณผ ์œ ์‚ฌํ•˜๊ฒŒ ์ฒซ ๋ฒˆ์งธ Parameter ๋กœ ์ž๊ธฐ ์ž์‹ ์„ ์ œ๊ณตํ•ด์•ผํ•˜๋ฉฐ, ์ž๊ธฐ ์ž์‹ ์˜ ํƒ€์ž… ์ •๋ณด๋ฅผ ํฌํ•จํ•ด์•ผํ•œ๋‹ค.

function greet(this: { name: string }, age: number) {
  console.log(`Hello, ${this.name}! I'm ${age} years old`);
}


๋”ฐ๋ผ์„œ Constructor Function ์—ญ์‹œ ํƒ€์ž…๋งŒ ๋ถ™์—ฌ ์‚ฌ์šฉํ•˜๋ ค ํ•˜๋ฉด ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•˜๋ฏ€๋กœ ๋ช…ํ™•ํ•œ this๋ฅผ ์ œ๊ณตํ•ด์•ผํ•œ๋‹ค.

interface IPerson {
  name: string;
  age: number;
  greet(): void;
}

function Person(this: IPerson, name: string, age: number) {
  this.name = name;
  this.age = age;

  this.greet = function () {
    console.log(
      `Hello, my name is ${this.name} and I'm ${this.age} years old.`
    );
  };
}

์‚ฌ์‹คโ€ฆ ์ด์ •๋„๋กœ boiler-code ๋ฅผ ๋งŽ์ด ๋งŒ๋“ค๊ฑฐ๋ฉด ์ฐจ๋ผ๋ฆฌ Class ๋ฌธ๋ฒ•์„ ์‚ฌ์šฉํ•˜๊ฑฐ๋‚˜ ์™„์ „ํžˆ ํ•จ์ˆ˜ํ˜•์œผ๋กœ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ๋‚ซ๋‹ค.

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

  greet() {
    console.log(
      `Hello, my name is ${this.name} and I'm ${this.age} years old.`
    );
  }
}

๋˜๋Š”

function Person(name: string, age: number) {
  let _name = name;
  let _age = age;

  function greet() {
    console.log(`Hello, my name is ${_name} and I'm ${_age} years old.`);
  }

  return {
    greet,
  };
}


3 ) strictNullChecks

์œ„ Make TypeScript more Strictly ์—์„œ ์ด๋ฏธ ํ•œ ๋ฒˆ ์‚ดํŽด๋ณด์•˜๋“ฏ์ด TypeScript ์˜ ๋ชจ๋“  ํƒ€์ž…์ด ๊ธฐ๋ณธ์ ์œผ๋กœ null๊ณผ undefined๋ฅผ ํฌํ•จํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ด๊ฒƒ์„ ์ œ์™ธ์‹œ์ผœ์ฃผ๋Š” ์˜ต์…˜์ด๋‹ค.

์ด๊ฑธ ์ฒดํฌํ•ด์ฃผ์ง€ ์•Š์œผ๋ฉด ๋ชจ๋“  ํƒ€์ž…์ด ์‚ฌ์‹ค์ƒ Optional ํƒ€์ž…์ด ๋˜์–ด๋ฒ„๋ฆฐ๋‹ค. ํ•„์š”์— ์˜ํ•ด Union ํƒ€์ž…์„ ์ด์šฉํ•ด Optional์„ ๋งŒ๋“œ๋Š” ๊ฒƒ์ด ์•„๋‹Œ ๋ชจ๋“  ํƒ€์ž…์ด Optional ์ด ๋˜๋Š” ๊ฒƒ์€ ๊ฒฐ๊ตญ JavaScript ์™€ ํฐ ์ฐจ์ด๊ฐ€ ์—†์–ด์ง€๋Š” ๊ฒƒ์ด๋‹ค.


4 ) strictFunctionTypes

Type Compatibility ์—์„œ ์‚ดํŽด๋ณธ ๊ฒƒ์ฒ˜๋Ÿผ TypeScript ๋Š” ๋‹ค๋ฅธ ์–ธ์–ด์™€ ๋‹ฌ๋ฆฌ ๊ธฐ๋ณธ์ ์œผ๋กœ Sub-Type ์ด Super-Type ์„ ์ƒ์œ„ ํ˜ธํ™˜ํ•˜๋Š” ๊ฒƒ์ด ๊ฐ€๋Šฅํ•œ ๋ฌธ์ œ๋ฅผ ์ œ๊ฑฐํ•˜๋Š” ์˜ต์…˜์ด๋‹ค.

ํ•จ์ˆ˜์˜ arguments ์— ๋Œ€ํ•œ ํƒ€์ž… ๊ฒ€์‚ฌ๋ฅผ ๊ฐ•ํ™”ํ•ด ๋‹ค๋ฅธ ์–ธ์–ด์™€ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ Super-Type ์ด Sub-Type ์„ ํ•˜์œ„ ํ˜ธํ™˜ ํ•˜๋Š” ๊ฒƒ๋งŒ ํ—ˆ์šฉํ•˜๋„๋ก ํ•œ๋‹ค(๋‹จ์ˆœํžˆ parameter ์™€ argument ํƒ€์ž…์„ ๊ฒ€์‚ฌํ•˜๋Š” ๊ฒƒ์€ ํ•ด๋‹น ์˜ต์…˜ ํ™œ์„ฑํ™”์™€ ๋ฌด๊ด€ํ•˜๊ฒŒ ๊ธฐ๋Šฅํ•œ๋‹ค. ์ด๊ฒƒ์€ Super-Type ๊ณผ Sub-Type ์˜ ์˜ฌ๋ฐ”๋ฅธ ๊ด€๊ณ„๋ฅผ ๊ฒ€์‚ฌํ•˜๊ธฐ ์œ„ํ•œ ์„ค์ •์ด๋‹ค).


5 ) strictPropertyInitialization

class Person {
  private name: string;
  private age: number;

  constructor() { }

  greet() {
    console.log(
      `Hello, my name is ${this.name} and I'm ${this.age} years old.`
    );
  }
}

์™€ ๊ฐ™์ด Class ์˜ Properties ๋ฅผ ์ดˆ๊ธฐํ™” ํ•˜์ง€ ์•Š์„ ๊ฒฝ์šฐ ์—๋Ÿฌ๋ฅผ ๋ฐœ์ƒ์‹œํ‚ค๋Š” ์˜ต์…˜์œผ๋กœ, TypeScript ์˜ Class ๋ฅผ ์ข€ ๋” Class ๋‹ต๊ฒŒ ๋งŒ๋“ค์–ด์ฃผ๋Š” ์˜ต์…˜์ด๋‹ค.

๋ฐ˜๋“œ์‹œ ์ƒ์„ฑ์ž๋ฅผ ์‚ฌ์šฉํ•ด ์ดˆ๊ธฐํ™”๋ฅผ ์‹œ์ผœ์ฃผ๊ฑฐ๋‚˜

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

  greet() {
    console.log(
      `Hello, my name is ${this.name} and I'm ${this.age} years old.`
    );
  }
}

๊ธฐ๋ณธ๊ฐ’์„ ์ œ๊ณตํ•ด์•ผํ•œ๋‹ค.

class Person {
  private name: string = 'John';
  private age: number = 23;

  constructor() {}

  greet() {
    console.log(
      `Hello, my name is ${this.name} and I'm ${this.age} years old.`
    );
  }
}


Classes ์˜ ์ดˆ๊ธฐํ™”๋Š” ์—๋Ÿฌ์— ์˜ํ•ด ์‹คํŒจํ•  ์ˆ˜๋„ ์žˆ์ง€๋งŒ, ์˜๋„์ ์œผ๋กœ ์ง€์—ฐ์‹œ์ผœ์•ผ ํ•  ํ•„์š”๊ฐ€ ์žˆ๋Š” ๊ฒฝ์šฐ๋„ ์žˆ๋‹ค. ์ดˆ๊ธฐํ™”๋ฅผ ํ•˜๋Š” ๋™์•ˆ ๊ฐ’์„ ์„ค์ •ํ•  ์ˆ˜ ์—†์–ด Optional Property Types ๋ฅผ ํ•„์š”๋กœ ํ•˜๋Š” ๊ฒฝ์šฐ๋‹ค. TypeScript ์—ญ์‹œ ์ด๋ฅผ ์ง€์›ํ•˜๋ฉฐ, ? ๋˜๋Š” !๋ฅผ ์ ์ ˆํžˆ ์‚ฌ์šฉํ•ด Classes ๋ฅผ ์ƒ์„ฑํ•˜๋ฉฐ, Properties ์˜ ์ดˆ๊ธฐํ™”๋ฅผ ์ง€์—ฐ์‹œํ‚ฌ ์ˆ˜ ์žˆ๋‹ค. ๋ฌผ๋ก , ์ด์— ๋Œ€ํ•œ ์ฑ…์ž„์ด ๊ฐœ๋ฐœ์ž์—๊ฒŒ ์ฃผ์–ด์ง„๋‹ค(?๋Š” constructor ์— ๋‹จ์ถ•ํ˜•์œผ๋กœ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ์ง€๋งŒ !๋Š” constructor ๋ฅผ ํ†ตํ•ด ์ž‘์„ฑํ•  ์ˆ˜ ์—†๋‹ค).

class Person {
  private name!: string;

  constructor(name: string, private age?: number) {}

  async init(name: string, age?: number) {
    this.name = name;
    this.age = age;
  }

  greet() {
    console.log(
      `Hello, my name is ${this.name} and I'm ${this.age} years old.`
    );
  }
}


6 ) strictBindCallApply

Function์˜ ๋‚ด์žฅ ํ•จ์ˆ˜์ธ bind, call, apply๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ ํ•จ์ˆ˜ ํ˜ธ์ถœ๊ณผ ๋‹ฌ๋ฆฌ ํƒ€์ž… ์ฒดํฌ๋ฅผ ํ•˜์ง€ ์•Š๋Š”๋‹ค. ์ด ์„ค์ •์„ ํ™œ์„ฑํ™” ์‹œ์ผœ์•ผ์ง€๋งŒ ์—„๊ฒฉํ•œ ์ฒดํฌ๋ฅผ ํ•œ๋‹ค.

function sum(a: number, b: number): number {
  return a + b;
}

sum('1', '2');   // error
sum.call(null, '1', '2');  // OK!

์ด ํ”„๋กœํผํ‹ฐ๋ฅผ ํ™œ์„ฑํ™” ์‹œํ‚ค๋ฉด ์ด์ œ bind, call, apply์—๋„ ์—„๊ฒฉํ•œ ํƒ€์ž… ๊ฒ€์‚ฌ๊ฐ€ ์ถ”๊ฐ€๋œ๋‹ค.

sum('1', '2');   // error
sum.call(null, '1', '2');  // error


7 ) alwaysStrict

์ปดํŒŒ์ผ๋˜๋Š” ๋ชจ๋“  JavaScript ํŒŒ์ผ ์ƒ๋‹จ์— "use strict"๋ฅผ ํฌํ•จ์‹œ์ผœ ๋Ÿฐํƒ€์ž„ ์—”์ง„์ด ์ฝ”๋“œ๋ฅผ strict ๋ชจ๋“œ๋กœ ๋ถ„์„ํ•˜๋„๋ก ํ•˜๋Š” ์˜ต์…˜์ด๋‹ค.


5. Interfaces ๐Ÿ‘ฉโ€๐Ÿ’ป

TypeScript ์˜ Interfaces ๋Š” JavaScript ์— ์กด์žฌํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ๋‹ค๋ฅธ ์–ธ์–ด์™€ ๋‹ฌ๋ฆฌ Runtime ์ด ์•„๋‹Œ ์˜ค์ง Compile-time ์—๋งŒ ์‚ฌ์šฉ๋œ๋‹ค. ์ฆ‰, ์ปดํŒŒ์ผ ๊ณผ์ •์—์„œ ์ œ๊ฑฐ๋˜์–ด ์‹ค์ œ ๋ฐฐํฌ๋˜๋Š” ์ฝ”๋“œ์—๋Š” ๋‚จ์ง€ ์•Š๊ฒŒ ๋˜๋Š” ๊ฒƒ์ด๋‹ค. ๊ธฐ๋ณธ์ ์œผ๋กœ ํ•˜๊ณ ์ž ํ•˜๋Š” ์—ญํ• ์ด๋‚˜ ๋ชฉ์ ์ด ๋‹ค๋ฅธ ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์–ธ์–ด์ฒ˜๋Ÿผ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•จ์ด๊ธฐ ๋•Œ๋ฌธ์— ํฌ๊ฒŒ ๋‹ค๋ฅด์ง€ ์•Š์ง€๋งŒ TypeScript ๋งŒ์˜ ํŠน์ง•์€ ์•Œ์•„๋‘ฌ์•ผํ•œ๋‹ค.

1. Optional Properties

ํ”ํžˆ ์ ‘ํ•˜๊ธฐ ์‰ฌ์šด ๋ฐฉ๋ฒ•์€ ๋‹ค๋ฅธ ์–ธ์–ด์™€ ๋™์ผํ•˜๊ฒŒ Properties ์ž์ฒด๋ฅผ Optional๋กœ ์„ค์ •ํ•˜๋Š” ๊ฒƒ์ด๋‹ค.

interface Person {
  readonly country: string;
  name: string;
  age?: number
}

๊ทธ๋ฆฌ๊ณ  ๋‹ค๋ฅธ ๋ฐฉ๋ฒ•์€ Index Signatures ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด๋‹ค.

interface Person {
  readonly country: string;
  name: string;
  age?: number;
  [index: string]: any;
}

์ƒ๊ธด ๊ฒƒ๊ณผ ์ด๋ฆ„์„ ๋ณด๋ฉด Swift Subscripts ์™€ ์œ ์‚ฌํ•  ๊ฒƒ ๊ฐ™์ง€๋งŒ ๋‹ค๋ฅด๋‹ค. ์ผ๋‹จ ์ด๊ฒƒ์€ interface์ž„์„ ๋ช…์‹ฌํ•˜์ž. ์ฆ‰, ๊ตฌํ˜„์ฒด๊ฐ€ ์•„๋‹ˆ๋ผ๋Š” ์˜๋ฏธ์ด๋‹ค.

2. Index Signatures

์šฐ์„ , Index Signature๋Š” number, string, symbol์„ ํƒ€์ž…์œผ๋กœ Index Type ์œผ๋กœ ๊ฐ€์งˆ ์ˆ˜ ์žˆ๋‹ค.

Number Index Signatures

number๋ฅผ index signature ๋กœ ์‚ฌ์šฉํ•˜๋ฉด ์ด property ๋Š” iterable ์ด ๊ฐ€๋Šฅํ•œ ํƒ€์ž…์„ ์˜๋ฏธํ•œ๋‹ค.

interface StringArray {
  [index: number]: string;
}

const stringArray: StringArray = ['a', 'b', 'c', 'd'];
const anotherStringArray: StringArray = 'qerty';

console.log(stringArray[1], anotherStringArray[2]); // b r
interface NumberArray {
  [index: number]: number;
}

const numberArray: NumberArray = [1, 2, 3, 4];
console.log(numberArray[1], numberArray[2]); // 2 3
interface Dog extends Animal {
  breed: string;
}

interface DogArray {
  [index: number]: Dog;
}

const dog1: Dog = { name: '๋‘๋ถ€', breed: 'Labrador' };
const dog2: Dog = { name: '์น˜์ฆˆ', breed: 'Husky' };
const dog3: Dog = { name: 'ํ‘ธ๋”ฉ', breed: 'Poodle' };

const dogArray: DogArray = [dog1, dog2, dog3];

์—ฌ๊ธฐ์„œ ์ค‘์š”ํ•œ ๊ฒƒ์€ Index Signature ์˜ key ํƒ€์ž…์ด number ๋ผ๋Š” ๊ฒƒ์ด์ง€ ํ•ด๋‹น ์ธํ„ฐํŽ˜์ด์Šค์˜ parameter ํƒ€์ž…์ด number ๊ฐ€ ์•„๋‹ˆ๋ผ๋Š” ๊ฒƒ์ด๋‹ค. ์ข€ ๋” ์ž์„ธํ•œ ์ดํ•ด๋ฅผ ์œ„ํ•ด ์•„๋ž˜ String Index Signatures ๋ฅผ ๋ณด์ž.


String Index Signatures

interface NumberDictionary {
  [index: string]: number;
  volunteers: number;
}

์™€ ๊ฐ™์ด Index Signature ๋กœ ์ƒ์„ฑํ•œ parameter ์˜ ํƒ€์ž…์ด number ์ด๋ฏ€๋กœ, ๋‹ค๋ฅธ properties ์—ญ์‹œ number ํƒ€์ž…์ด์–ด์•ผํ•œ๋‹ค.

interface NumberDictionary {
  [index: string]: number;
  programName: string;  // type error
}

์ด๊ฒƒ์€ ๋ถˆ๊ฐ€๋Šฅํ•œ ์ •์˜๋‹ค. someDictionary['foo']๋ฅผ ํ•œ ๊ฒฐ๊ณผ๊ฐ€ number ์ธ๋ฐ programName ์ด string ์ด ๋˜๋Š” ๊ฒƒ์ด ๋ถˆ๊ฐ€๋Šฅํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ์ด๊ฒƒ์ด ๊ฐ€๋Šฅํ•˜๋ ค๋ฉด ์•„๋ž˜ ๊ฐ™์ด Index Signature ๋กœ ์ƒ์„ฑํ•œ parameter ์˜ ํƒ€์ž… ์—ญ์‹œ string ์ด ๋˜์–ด์•ผ ํ•œ๋‹ค.

interface StringDictionary {
  [index: string]: string;
  programName: string;
}


ํ•˜์ง€๋งŒ, Dictionary Type ์ฆ‰, TypeScript ์—์„œ Object ๋Š” string, number, etcโ€ฆ ์™€ ๊ฐ™์ด ๋‹ค์–‘ํ•œ ํƒ€์ž…์˜ properties ๋ฅผ ์ €์žฅํ•  ์ˆ˜ ์žˆ๋Š” ์ปจํ…Œ์ด๋„ˆ๋‹ค. ์ด๊ฒƒ์„ ์œ„ํ•ด ์šฐ๋ฆฌ๋Š” Index Signatures ๊ฐ€ ๊ฐ€์งˆ ์ˆ˜ ์žˆ๋Š” ํƒ€์ž…์„ Union Type์„ ์‚ฌ์šฉํ•ด ๋ณต์ˆ˜ ํ—ˆ์šฉ์„ ํ•  ์ˆ˜ ์žˆ๋‹ค.

interface VolunteerRecruit {
  [index: string]: number | string;
  volunteers: number;
  programName: string;
}

const africaRecruit: VolunteerRecruit = {
  volunteers: 10,
  programName: '2023 12์›” ์•„ํ”„๋ฆฌ์นด ์ž์›๋ด‰์‚ฌ',
};

console.log(
    `${africaRecruit['programName']}์˜ ์ง€์›์ž ์ˆ˜๋Š” ${africaRecruit['volunteers']}๋ช… ์ž…๋‹ˆ๋‹ค.`
);
2023 12์›” ์•„ํ”„๋ฆฌ์นด ์ž์›๋ด‰์‚ฌ์˜ ์ง€์›์ž ์ˆ˜๋Š” 10๋ช… ์ž…๋‹ˆ๋‹ค.

์—ฌ๊ธฐ์„œ ์ค‘์š”ํ•œ ๊ฒƒ ์—ญ์‹œ Index Signature ์˜ key ํƒ€์ž…์ด string ์ด๋ผ๋Š” ๊ฒƒ์ด์ง€ ํ•ด๋‹น ์ธํ„ฐํŽ˜์ด์Šค์˜ parameter ํƒ€์ž…์ด string ์ด ์•„๋‹ˆ๋ผ๋Š” ๊ฒƒ์ด๋‹ค.

์ฆ‰, Index Signatures ๊ฐ€ number ๋ผ๋Š” ๊ฒƒ์€ foo[3]๊ณผ ๊ฐ™์ด ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•œ ๊ฒƒ์œผ๋กœ Array ์™€ ๊ฐ™์€ Iterable ํƒ€์ž…์„ ์ •์˜ํ•˜๊ธฐ ์œ„ํ•œ ๊ฒƒ์ด๋ผ ๋ณด๋ฉด ๋œ๋‹ค. ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ Index Signatures ๊ฐ€ string ์ด๋ผ๋Š” ๊ฒƒ์€ bar['baz']์™€ ๊ฐ™์ด ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•œ ๊ฒƒ์œผ๋กœ Object ์™€ ๊ฐ™์€ Key-Value ํƒ€์ž…์„ ์ •์˜ํ•˜๊ธฐ ์œ„ํ•œ ๊ฒƒ์ด๋ผ ๋ณด๋ฉด ๋œ๋‹ค.

๋งŒ์•ฝ JavaScript ์˜ Object, Java ์˜ Map, Swift ์˜ Dictionary ์— [String: Any]์™€ ๊ฐ™์€ ๋ฐฉ์‹์œผ๋กœ ๋ชจ๋“  ๋ฐ์ดํ„ฐ๋ฅผ ์ €์žฅํ•  ์ˆ˜ ์žˆ๋Š” Key-Value Types ๋กœ ์‚ฌ์šฉํ•˜๊ณ ์ž ํ•œ๋‹ค๋ฉด unknown์„ ์‚ฌ์šฉํ•ด ๋ชจ๋“  ํƒ€์ž…์„ Dynamic ์œผ๋กœ ๋ฐ›์„ ์ˆ˜ ์žˆ๋‹ค.

interface VolunteerRecruit {
  [index: string]: unknown;
  volunteers: number;
  programName: string;
}


Symbol Index Signatures

symbol ์„ Index Signature ์— ์‚ฌ์šฉํ•  ์ผ์ด ๋งŽ์„ ๊ฒƒ ๊ฐ™์ง€๋Š” ์•Š๋‹ค. string ๊ณผ ์œ ์‚ฌํ•˜๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, string ์„ ํ†ตํ•œ ์ ‘๊ทผ์„ ๋ง‰๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

interface Member {
  [index: symbol]: string; // for name
  age: number;
}

const gildongId = Symbol('id8784');

const member: Member = {
  [gildongId]: 'ํ™๊ธธ๋™',
  age: 28,
};

// console.log(member['id8784']);  // error
console.log(member[gildongId]); // ํ™๊ธธ๋™

3. Type Alias & Interface

TypeScript ์—์„œ interface์™€ type์€ ๋งŽ์€ ๊ณณ์—์„œ ํ˜ผ์šฉ๋˜๋ฉฐ ์„œ๋กœ ๋ฐ”๊พธ์–ด ์‚ฌ์šฉํ•ด๋„ ๋Œ€๋ถ€๋ถ„ ํ˜ธํ™˜์ด ๊ฐ€๋Šฅํ•˜๋‹ค.

Functions

type ArithmeticCalc = (lhs: number, rhs: number) => number;

let addTwoInts: ArithmeticCalc = (lhs: number, rhs: number) => lhs + rhs;
let multiplyTwoInts: ArithmeticCalc = (a: number, b: number) => a * b;
interface ArithmeticCalc {
  (lhs: number, rhs: number): number;
}

let addTwoInts: ArithmeticCalc = (lhs: number, rhs: number) => lhs + rhs;
let multiplyTwoInts: ArithmeticCalc = (a: number, b: number) => a * b;


Array

type PersonList = string[];

const students: PersonList = ['Alice', 'Bob', 'Charlie'];

type์˜ ๋ฌธ๋ฒ•์€ ๋‹ค๋ฅธ ์–ธ์–ด์™€ ํฌ๊ฒŒ ๋‹ค๋ฅด์ง€ ์•Š๋‹ค.

interface PersonList {
  [index: number]: string;
}

const students: PersonList = ['Alice', 'Bob', 'Charlie'];

interface๋Š” ์ด๋ฅผ ์œ„ํ•ด ์œ„์—์„œ ๋ณธ Number Index Signatures ๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.


Intersection

interface Breakfast {
  breakfast: string;
}

interface Lunch {
  lunch: string;
}

interface Dinner {
  dinner: string;
}

๋ฅผ ํ™•์žฅํ•ด ์ƒˆ ํƒ€์ž…์„ ๋งŒ๋“ค์–ด๋ณด์ž.

type DayMeal = Breakfast & Lunch & Dinner;

const todayMeal: DayMeal = {
  breakfast: 'hamburger',
  lunch: 'pizza',
  dinner: 'burger',
};
interface DayMeal extends Breakfast, Lunch, Dinner {}

const todayMeal: DayMeal = {
  breakfast: 'hamburger',
  lunch: 'pizza',
  dinner: 'burger',
};


Union Types

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

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

type PetType = Bird | Fish;

interface Pet extends PetType {}  // error, TS2312
class Pet implements PetType {}   // error, TS2422
  • Union Types๋Š” Type Alias๋กœ๋งŒ ํ‘œํ˜„ ๊ฐ€๋Šฅํ•˜๋‹ค.
  • Union Types๋Š” ์ธํ„ฐํŽ˜์ด์Šค์˜ extends ๋‚˜ ํด๋ž˜์Šค์˜ implements ์— ์‚ฌ์šฉ๋  ์ˆ˜ ์—†๋‹ค.

type์ด ํด๋ž˜์Šค implements ์— ์‚ฌ์šฉ ๋ถˆ๊ฐ€๋Šฅํ•œ ๊ฒƒ์€ ์•„๋‹ˆ๋‹ค.

type AnimalType = {
  name: string;
  color: string;
  kind: string;
  weight: number;
};

class Animal implements AnimalType {
  name: string = 'Swan';
  color: string = 'white';
  kind: string = 'bird';
  weight: number = 5;
}

์˜ค์ง Union Type์ด ์‚ฌ์šฉ ๋ถˆ๊ฐ€๋Šฅํ•œ ๊ฒƒ์ด๋‹ค.


Declaration Merging

์ด๋ฒˆ์—” Union Types์™€ ๋ฐ˜๋Œ€๋กœ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ํ†ตํ•ด์„œ๋งŒ ๊ฐ€๋Šฅํ•œ ๊ฒƒ์„ ์†Œ๊ฐœํ•œ๋‹ค.

interface MergingInterface {
  foo: string;
}

interface MergingInterface {
  bar: string;
}

const something: MergingInterface = {
  foo: 'yellow',
  bar: 'blue',
};

๋™์ผํ•œ ์ด๋ฆ„์œผ๋กœ ๋ณต์ˆ˜์˜ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์„ ์–ธํ•  ์ˆ˜ ์žˆ์„ ๋ฟ ์•„๋‹ˆ๋ผ ์ž๋™์œผ๋กœ ๋จธ์ง€๊ฐ€ ๋œ๋‹ค. Type Alias ๋Š” ์ค‘๋ณต ์„ ์–ธ์„ ํ—ˆ์šฉํ•˜์ง€ ์•Š์•„ ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค.

์ธํ„ฐํŽ˜์ด์Šค์˜ ๋จธ์ง€๋Š” HTML elements ๋ฅผ ํ™•์žฅํ•˜๊ฑฐ๋‚˜ ํ•  ๋•Œ ๊ธฐ์กด์— ์žˆ๋Š” ๊ฒƒ๋„ ์‚ฌ์šฉํ•˜๊ณ , ๋‚ด๊ฐ€ ์ถ”๊ฐ€ํ•œ ๊ฒƒ๋„ ์‚ฌ์šฉํ•˜๋„๋ก ํ•ฉ์ณ์•ผ ํ•  ๋•Œ ์œ ์šฉํ•˜๊ฒŒ ์‚ฌ์šฉ๋œ๋‹ค.


6. Classes ๐Ÿ‘ฉโ€๐Ÿ’ป

1. Initialization

Classes ์šฉ๋„๋‚˜ ๋ฌธ๋ฒ•, ๊ธฐ๋Šฅ์€ ๋‹ค๋ฅธ ์–ธ์–ด์™€ ์œ ์‚ฌํ•˜๋‹ค. TypeScript ์˜ ๋ฌธ๋ฒ•์  ํŠน์ง•์„ ์œ„์ฃผ๋กœ ์‚ดํŽด๋ณด์ž.

class Person {
  name: string;
  private age: number;

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

๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ถ•์•ฝํ•ด์„œ ํ‘œํ˜„์ด ๊ฐ€๋Šฅํ•˜๋‹ค.

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

2. Getters & Setters

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

  get name(): string { return this.name; }  // error, Duplicate identifier 'name'.
}

๊ธฐ๋ณธ์ ์œผ๋กœ JavaScript ์˜ ES6 Classes ๋ฌธ๋ฒ•์—์„œ ์กด์žฌํ•˜๋Š” Properties ์— ๋Œ€ํ•œ Gatters์™€ Setters ๊ฐ€ ์ž๋™์œผ๋กœ ์ƒ์„ฑ๋œ๋‹ค. ๋”ฐ๋ผ์„œ ๊ฐœ๋ฐœ์ž๊ฐ€ ๋งŒ๋“ค๋ ค๊ณ  ํ•˜๋ฉด ์ค‘๋ณต ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒ๋œ๋‹ค. ๋ฉ”์„œ๋“œ ํ˜•ํƒœ๋กœ ์ •์˜ํ•˜์ง€๋งŒ, ์‚ฌ์‹ค์ƒ ์ด๊ฒƒ์€ Computed Properties ์— ๊ฐ€๊นŒ์šด ํ˜•ํƒœ๋‹ค.

class Person {
  constructor(
    public _name: string,
    private age: number,
    private changeName = 0
  ) {}

  get name(): string {
    console.log(`Log: ${this._name}์ด ์กฐํšŒ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.`);
    return this._name;
  }

  set name(value: string) {
    console.log(`Log: ์ด๋ฆ„์ด ${++this.changeName}๋ฒˆ ๊ฐœ๋ช…๋˜์—ˆ์Šต๋‹ˆ๋‹ค.`);
    this._name = value;
  }
}

const p: Person = new Person('John', 30);

console.log(`์•ˆ๋…•ํ•˜์„ธ์š”. ์ œ ์ด๋ฆ„์€ ${p.name}์ž…๋‹ˆ๋‹ค.`);

p.name = 'Kevin';
Log: John์ด ์กฐํšŒ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.
์•ˆ๋…•ํ•˜์„ธ์š”. ์ œ ์ด๋ฆ„์€ John์ž…๋‹ˆ๋‹ค.
Log: ์ด๋ฆ„์ด 1๋ฒˆ ๊ฐœ๋ช…๋˜์—ˆ์Šต๋‹ˆ๋‹ค.


๋˜ํ•œ ์ด๋ฅผ ์ž˜ ํ™œ์šฉํ•˜๋ฉด private(set)๊ณผ ๊ฐ™์ด ์ ‘๊ทผ ์ œ์–ด๋ฅผ ๋‹ค๋ฅด๊ฒŒ ์„ค์ •ํ•  ์ˆ˜ ์žˆ๋‹ค.

class SomeClass {
    private(set) var id: String = ""

    func setId(_ id: String) {
        self.id = id
    }
}

๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๋‹ค.

class SomeClass {
  private _id: String = '';

  get id(): String {
    return this._id;
  }

  setId(id: String) {
    this._id = id;
  }
}
const someClass = new SomeClass();

someClass.id = 'A'; // error: Cannot assign to 'id' because it is a read-only property.
someClass.setId('A');
console.log(someClass.id);  // A

3. Index Signatures in Classes

์ผ๋ฐ˜์ ์œผ๋กœ ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์–ธ์–ด๊ฐ€ Dynamic Types ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” Dictionaries ์™€ ๊ฐ™์€ ํƒ€์ž…์„ ๊ฐ–๊ณ  ์žˆ์ง€๋งŒ Classes ์™€ ๊ฐ™์€ ํƒ€์ž…์„ ์ •์˜ํ•˜๊ณ  ์‚ฌ์šฉํ•  ๋•Œ, ์ด๋Ÿฌํ•œ ํƒ€์ž…๋“ค์€ ์ž์‹ ์˜ properties ์— ๋Œ€ํ•œ ๋™์  ํƒ€์ž…์„ ํ—ˆ์šฉํ•˜์ง€ ์•Š๋Š”๋‹ค. ๋งŒ์•ฝ, Classes ๋‚ด๋ถ€์— ๋™์  ํƒ€์ž…์„ ๊ฐ€์งˆ ์ˆ˜ ์žˆ๋Š” Dictionary Type Properties ๋ฅผ ์ถ”๊ฐ€ํ•˜๊ณ , ์—ฌ๊ธฐ์— ๋™์  ๋ฐ์ดํ„ฐ๋ฅผ ๋„ฃ์–ด์•ผํ•œ๋‹ค.

enum Sex: String {
    case male, female
}

typealias MyClass = [String: Sex]

var class1: MyClass = [:]
class1["๊น€์ฒ ์ˆ˜"] = .male
class1["์ด์˜ํฌ"] = .female
class1["๋ฐ•ํฅ์ˆ˜"] = .male

var class2: MyClass = [:]
class2["์œ ์†Œ์˜"] = .female
class2["๊น€์ง€์€"] = .female
class2["์†ก์˜ํ˜ธ"] = .male

์œ„์™€ ๊ฐ™์ด Dictionaries ๋ฅผ ์ด์šฉํ•œ ๋™์  ํƒ€์ž…์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์œผ๋‚˜, Classes ์™€ ๊ฐ™์€ ๊ฐ์ฒด๋ฅ˜ ๋ฐ์ดํ„ฐ๋Š” ์ •์  ํƒ€์ž…์ด๊ธฐ ๋•Œ๋ฌธ์— ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋™์  ํƒ€์ž…์˜ properties ๋ฅผ ๋งŒ๋“ค์–ด ์ €์žฅํ•ด์•ผํ•œ๋‹ค.

enum Sex: String {
    case male, female
}

struct MyClass {
    var student: [String: Sex] = [:]
}

var class1: MyClass = MyClass()
class1.student["๊น€์ฒ ์ˆ˜"] = .male
class1.student["์ด์˜ํฌ"] = .female
class1.student["๋ฐ•ํฅ์ˆ˜"] = .male

var class2: MyClass = MyClass()
class2.student["์œ ์†Œ์˜"] = .female
class2.student["๊น€์ง€์€"] = .female
class2.student["์†ก์˜ํ˜ธ"] = .male

ํ•˜์ง€๋งŒ TypeScript ์˜ Classes ๋Š” ์‚ฌ์‹ค Object ๊ณ , ์ด๊ฒƒ์„ ๋งŒ๋“œ๋Š” ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์‰ฝ๊ฒŒ ๋งŒ๋“  Syntactic Sugar ์— ๊ฐ€๊นŒ์šด Dynamic Type Language ์ด๊ธฐ ๋•Œ๋ฌธ์— String Index Signatures ๋ฅผ ์‚ฌ์šฉํ•ด ๋‹ค์Œ๊ณผ ๊ฐ™์ด Classes ์— ๋™์ ์œผ๋กœ ์„ ์–ธํ•˜๋Š” ๊ฒƒ์ด ๊ฐ€๋Šฅํ•˜๋‹ค.

type Sex = 'male' | 'female';

class MyClass {
  [index: string]: Sex;
}

const class1 = new MyClass();
class1['๊น€์ฒ ์ˆ˜'] = 'male';
class1['์ด์˜ํฌ'] = 'female';
class1['๋ฐ•ํฅ์ˆ˜'] = 'male';

const class2 = new MyClass();
class2['์œ ์†Œ์˜'] = 'female';
class2['๊น€์ง€์€'] = 'female';
class2['์†ก๋ช…ํ˜ธ'] = 'male';

4. Inheritance

TypeScript ์˜ ์ƒ์† ์—ญ์‹œ Override ๋ฅผ ํ†ตํ•ด ๋ฉ”์„œ๋“œ๋ฅผ ์ˆ˜์ •ํ•จ์€ ๋ฌผ๋ก , properties ์˜ Access Levels ๋ฅผ ๋ณ€๊ฒฝํ•˜๋Š” ๊ฒƒ ์—ญ์‹œ ๊ฐ€๋Šฅํ•˜๋‹ค. ๋˜ํ•œ, ๋ถ€๋ชจ์— ์ ‘๊ทผํ•  ๋•Œ super ํ‚ค์›Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ ์—ญ์‹œ ๋™์ผํ•˜๋‹ค.

class Vehicle {
  protected currentSpeed = 0;

  get description(): String {
    return `traveling at ${this.currentSpeed} miles per hour`;
  }

  makeNoise() {
    // do nothing - an arbitrary vehicle doesn't necessarily make a noise
  }
}
class Car extends Vehicle {
  override get description(): String {
    return `${super.description} in gear ${this.gear}`;
  }

  constructor(
    public gear: number = 1,
    public override currentSpeed: number = 0
  ) {
    super();
    this.gear = gear;
    this.currentSpeed = currentSpeed;
  }
}
const myCar = new Car();
myCar.gear = 5;
myCar.currentSpeed = 10;  // ์ƒ์†์„ ํ†ตํ•ด ์ ‘๊ทผ ๊ฐ€๋Šฅํ•˜๋„๋ก Access Level ์„ ๋ณ€๊ฒฝํ–ˆ๋‹ค.
console.log(myCar.description); // "traveling at 10 miles per hour in gear 5"

5. Abstract Classes

Swift ์—์„œ๋Š” Protocols ์— Default Implementations ๋ฅผ ์ œ๊ณตํ•  ์ˆ˜ ์žˆ๋‹ค. ๋˜ํ•œ Java ์—ญ์‹œ Java 8 ๋ถ€ํ„ฐ Interfaces ์— Default Methods ๋ฅผ ๊ตฌํ˜„ํ•˜๋Š” ๊ฒƒ์ด ๊ฐ€๋Šฅํ•˜๋‹ค.

๊ทธ๋Ÿผ์—๋„ Abstract Classes๊ฐ€ ์˜๋ฏธ๋ฅผ ๊ฐ–๋Š” ๊ฒƒ์€ Protocols ๋‚˜ Interfaces ๊ฐ€ ์˜๋ฏธ๋ฅผ ๊ฐ–๋Š” ๊ฒƒ์€ ๋ฉ”์„œ๋“œ์— ๋Œ€ํ•œ ๊ธฐ๋ณธ ๊ตฌํ˜„์ผ ๋ฟ, Instance Properties ๋ฅผ ๊ธฐ๋ณธ ๊ตฌํ˜„์œผ๋กœ ๊ฐ€์งˆ ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์€ ์•„๋‹ˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์šฐ๋ฆฌ์—๊ฒŒ ๋”์šฑ ์ค‘์š”ํ•œ ๊ฒƒ์€ TypeScript ์˜ Interfaces ๋Š” ๊ทธ ์–ด๋–ค ๊ธฐ๋ณธ ๊ตฌํ˜„๋„ ์ œ๊ณตํ•  ์ˆ˜ ์—†๋‹ค๋Š” ๊ฒƒ ๋•Œ๋ฌธ์ด๋‹ค.

abstract class AbstractPerson {
  protected _name: string = 'Mark';
  abstract setName(name: string): void;
  sayHello(): void {
    console.log(`Hello, I'm ${this._name}.`);
  }
}
interface IPerson {
  _name: string;
  setName(name: string): void;
}

7. Generics ๐Ÿ‘ฉโ€๐Ÿ’ป

1. Syntax

๋‹ค๋ฅธ ์–ธ์–ด์™€ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ Generic Types ๋ฅผ ์‚ฌ์šฉํ•œ ํ•จ์ˆ˜ ์„ ์–ธ์€ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ํ•œ๋‹ค.

function hello<T>(message: T): T {
  return message;
}
const hello = <T>(message: T): T => message;


๊ทธ๋Ÿฐ๋ฐ ์‚ฌ์šฉํ•  ๋•Œ ์ฃผ์˜ํ•ด์•ผํ•  ๊ฒƒ์ด ์žˆ๋‹ค.

hello('Hello World!');

๋ณดํ†ต ๋‹ค๋ฅธ ์–ธ์–ด์—์„œ ์œ„์™€ ๊ฐ™์ด ์‚ฌ์šฉํ•˜๋ฉด ๋ฌธ์ž์—ด๋กœ ์ถ”๋ก ๋œ๋‹ค. ํ•˜์ง€๋งŒ TypeScript ์—์„  ์ด๊ฒƒ์„ 'Hello World!'๋ผ๋Š” ํƒ€์ž…์œผ๋กœ ์ถ”๋ก ํ•ด๋ฒ„๋ฆฐ๋‹ค!!

์ฆ‰, string์ด ์•„๋‹Œ ๋‹ค์Œ๊ณผ ๊ฐ™์€ substring ํƒ€์ž…์ด ๋˜๋Š” ๊ฒƒ์ด๋‹ค.

type HelloWorld = 'Hello World!';

๋ฌผ๋ก , ์ด๋ ‡๊ฒŒ ํ•˜๋”๋ผ๋„ substring ์—ญ์‹œ string ์˜ ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ํฐ ๋ฌธ์ œ๋Š” ์—†๋‹ค. ํ•˜์ง€๋งˆ ์ด๊ฒƒ์˜ ํƒ€์ž…์ด string ์ด ์•„๋‹Œ 'Hello World!'๋ผ๋Š” substring ํƒ€์ž…์ด๋ผ๋Š” ๊ฒƒ์„ ์ธ์ง€ํ•˜๊ณ  ์‚ฌ์šฉํ•ด์•ผํ•œ๋‹ค.

๋งŒ์•ฝ, string, number ์™€ ๊ฐ™์€ ์ผ๋ฐ˜ํ™” ๋œ ํƒ€์ž…์„ ์‚ฌ์šฉํ•˜๋ ค๋ฉด ๋ฐ˜๋“œ์‹œ ์•„๋ž˜์™€ ๊ฐ™์ด ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•  ๋•Œ ์ง์ ‘ ํƒ€์ž…์„ ์„ค์ •ํ•ด์ค˜์•ผํ•œ๋‹ค.

hello<string>('Hello World!');
hello<number>(123);

2. Generics Array & Tuple

Array

function helloarray<T>(arr: T[]): T {
  return arr[0];
}

helloarray([1, 2, 3]);
helloarray(['a', 1, 'b', 2, 'c']);

์œ„์—์„œ ๋ณธ ๊ฒƒ์ฒ˜๋Ÿผ ์ด ๊ฒฝ์šฐ ํƒ€์ž…์€ [1, 2, 3]์ผ ๊ฒƒ ๊ฐ™์ง€๋งŒ Object ํƒ€์ž…์—์„œ๋Š” ๋‹ค๋ฅธ ์–ธ์–ด์™€ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ๊ทธ๊ฒƒ์˜ ํƒ€์ž…์ด ์ถ”๋Ÿฐ๋œ๋‹ค. ์ฆ‰,

number[] => number
(string | number)[] => string | number

ํƒ€์ž…์œผ๋กœ ์ถ”๋ก ๋œ๋‹ค.


Tuple

๋ฐ˜๋ฉด Tuple ์€ Array ์™€ ๋‹ฌ๋ฆฌ ์ด๋ฏธ ์ •ํ•ด์ง„ ํƒ€์ž…์ด๊ธฐ ๋•Œ๋ฌธ์—

function hellotuple<T, U>(tuple: [T, U]): T {
  return tuple[0];
}

hellotuple([1, 2]);
hellotuple(['a', 1]);

์˜ ํƒ€์ž…์€ ๊ฐ๊ฐ

[number, number] => number
[string, number] => string

ํƒ€์ž…์œผ๋กœ ์ •ํ™•ํžˆ ์ถ”๋ก ๋œ๋‹ค.

3. Generic Function Type Alias & Interface

์œ„์—์„œ Generic Functions ๋ฅผ ํ•จ์ˆ˜ Function Declaration ๊ณผ Function Expressions ์œผ๋กœ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ๋ณด์•˜๋‹ค. TypeScript ์ด๋ฏ€๋กœ ํ•จ์ˆ˜๊ฐ€ ์–ด๋–ค ๋ชจ์Šต์„ ์ทจํ•ด์•ผํ•˜๋Š”์ง€๋ฅผ ํ‘œํ˜„ํ•  ์ˆ˜ ์žˆ๋‹ค.

type HellloFunctionGeneric = <T>(message: T) => T;
interface HellloFunctionGeneric {
  <T>(message: T): T;
}

4. keyof

keyof๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๊ฐ์ฒด์˜ keys๋ฅผ ์ถ”์ถœํ•  ์ˆ˜ ์žˆ๋‹ค.

const Hobbies = [
  'Movie',
  'Music',
  'Reading',
  'Cooking',
  'Dancing',
  'Swimming',
] as const;

type Hobby = (typeof Hobbies)[number];

const oneHobby: Hobby = 'Reading';
const myHobbies: Hobby[] = ['Movie', 'Music', 'Reading', 'Cooking'];

keyof๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด Hobbies ๋ฐฐ์—ด๋กœ๋ถ€ํ„ฐ One of Hobbies ๋˜๋Š” Some of Hobbies ์™€ ๊ฐ™์€ ๋ฐฉ์‹์œผ๋กœ ํƒ€์ž…์„ ๋งŒ๋“ค์–ด ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.


์œ„์—์„œ ๋ณด์•˜๋“ฏ์ด TypeScript ์—์„œ keyof๋Š” ํƒ€์ž…์„ ๋‹ค๋ฃจ๋Š” ๋ฐ ๋งค์šฐ ๊ฐ•๋ ฅํ•œ ๋„๊ตฌ๋กœ ์‚ฌ์šฉ๋œ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์ด ํ‚ค์›Œ๋“œ๋Š” Generics ์™€ ํ•จ๊ป˜ ์‚ฌ์šฉํ•˜๋ฉด ๋” ๊ฐ•๋ ฅํ•œ ๋„๊ตฌ๊ฐ€ ๋œ๋‹ค.

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

const person: IPerson = {
  name: 'John',
  age: 36,
};

function getProp(obj: IPerson, key: keyof IPerson): IPerson[keyof IPerson] {
  return obj[key];
}

keyof๋ฅผ ์‚ฌ์šฉํ•ด ํ•˜๋“œ์ฝ”๋”ฉ ์—†์ด ๋™์ ์œผ๋กœ ํƒ€์ž…์„ ์„ค์ •ํ–ˆ์ง€๋งŒ ๋ฐ˜ํ™˜ ํƒ€์ž…์ด ์—ฌ์ „ํžˆ IPerson[โ€œnameโ€] | IPerson[โ€œageโ€] ๋ผ๋Š” Union Types ๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ๋ฌธ์ œ๊ฐ€ ์กด์žฌํ•œ๋‹ค. Generics ๋ฅผ ์‚ฌ์šฉํ•ด๋ณด์ž.

function getProp<T>(obj: T, key: keyof T): T[keyof T] {
  return obj[key];
}

const prop1 = getProp<IPerson>(person, 'name');

์ด์ œ IPerson[โ€œnameโ€] | IPerson[โ€œageโ€] ๋ณด๋‹ค๋Š” ํƒ€์ž…์ด ์ข€ ๋” ์ •ํ™•ํ•˜๊ฒŒ ํ‘œํ˜„๋˜์ง€๋งŒ ์—ฌ์ „ํžˆ string | number๋ผ๋Š” Union Types ๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค. keyof T๋ฅผ ํ•จ์ˆ˜๊ฐ€ ํ˜ธ์ถœ๋  ๋•Œ ํƒ€์ž…์ด ์ œํ•œ๋˜๋„๋ก ํ•˜๋ฉด ๋ฒ”์œ„๋ฅผ ๋” ์ขํž ์ˆ˜ ์žˆ์„ ๊ฒƒ ๊ฐ™๋‹ค. T๊ฐ€ ์ •ํ•ด์ง€๋ฉด, ์ด T๋กœ๋ถ€ํ„ฐ ์ œํ•œ๋œ key๋ฅผ ํƒ€์ž…์œผ๋กœ ๊ฐ–๋„๋ก ๋‘ ๋ฒˆ์งธ ๋ณ€์ˆ˜ K๋ฅผ ๋„์ž…ํ•ด๋ณด์ž.

function getProp<T, K extends keyof T>(obj: T, key: K): T[K] {
  return obj[key];
}

const prop1: string = getProp(person, 'name');
const prop2: number = getProp(person, 'age');

ํ•จ์ˆ˜๊ฐ€ ํ˜ธ์ถœ๋˜๋Š” ์ˆœ๊ฐ„ ๊ฐ๊ฐ

function getProp<IPerson, "name">(obj: IPerson, key: "name"): string
function getProp<IPerson, "age">(obj: IPerson, key: "age"): number

์™€ ๊ฐ™์ด ํƒ€์ž…์ด ๋ช…ํ™•ํžˆ ์ •์˜๋˜๊ธฐ ๋Œ€๋ฌธ์— ๋”์ด์ƒ Union Types ๋ฅผ ๋ฐ˜ํ™˜ํ•˜์ง€ ์•Š๋Š”๋‹ค.

์œ„์™€ ๊ฐ™์€ ๋ฐฉ๋ฒ•์œผ๋กœ setPropํ•จ์ˆ˜๋„ ์ •์˜ํ•  ์ˆ˜ ์žˆ๋‹ค.

function setProp<T, K extends keyof T>(obj: T, key: K, value: T[K]): void {
  obj[key] = value;
}

Reference

  1. ์ด์›…์žฌ, โ€œํ•œ ๋ฒˆ์— ๋๋‚ด๋Š” React์˜ ๋ชจ๋“  ๊ฒƒ ์ดˆ๊ฒฉ์ฐจ ํŒจํ‚ค์ง€, Part 6. TypeScript Essentialsโ€ fastcampus.co.kr. last modified unknown, Fast Campus.
  2. โ€œConditional Types.โ€ typescriptlang.org. accessed Dec. 23, 2023, TypeScript - Conditional Types.
  3. โ€œIntro to the TSConfig Reference.โ€ typescriptlang.org. accessed Dec. 24, 2023, TypeScript - TSConfig Reference.
  4. โ€œCompile on save.โ€ GitHub. Dec. 24, 2023, https://github.com/TypeStrong/atom-typescript#compile-on-save.
  5. โ€œtsconfig.json.โ€ TypeScript. access Dec. 24, 2023, [TypeScript - tsconfig].