2024-06-29.md
π‘DIL: μ΄νν°λΈ νμ μ€ν¬λ¦½νΈ
μ€ν°λ: μκ° CS, https://github.com/monthly-cs/2024-05-effective-typescript
μμ±μΌ: 2024-06-29 μμ±μ: dusunax
μμ΄ν 58: λͺ¨λ μλ°μ€ν¬λ¦½νΈ μμ±νκΈ° μ΄μ΄μ
νλ‘ν νμ λμ ν΄λμ€ μ¬μ©νκΈ°
- ES6 class ν€μλ(ν΄λμ€ κΈ°λ° λͺ¨λΈ) λμ
μ΄μ => νλ‘ν νμ
κΈ°λ°μ κ°μ²΄ λͺ¨λΈμ μ¬μ©νλ€.
- λ§μ΄κ·Έλ μ΄μ λμ μ½λμ νλ‘ν νμ μ΄ μλ€λ©΄ ν΄λμ€λ‘ λ°κΎΈλ κ²μ΄ μ’λ€. μ§κ΄μ μ΄κ³ κ°κ²°ν¨.
- VS Codeμλ TypeScriptλ₯Ό μν μ μ©ν 리ν©ν λ§ κΈ°λ₯μ΄ ν¬ν¨λμ΄ μμ΅λλ€. μλ₯Ό λ€μ΄, ν¨μ μΆμΆ λ° μμ μΆμΆ κΈ°λ₯μ΄ μμ΅λλ€. μΆμΆνκ³ μ νλ μμ€ μ½λλ₯Ό μ νν λ€μ, μ’μΈ‘μ λνλλ μ ꡬ μμ΄μ½μ ν΄λ¦νκ±°λ (β.)λ₯Ό λλ¬ μ¬μ© κ°λ₯ν 리ν©ν λ§ μ΅μ
μ νμΈν μ μμ΅λλ€.
https://code.visualstudio.com/Docs/languages/typescript#_refactoring
// ν΄λμ€
function Person(first, last) {
// ν¨μλͺ
μλ ...μ΄ λνλμΌ νλλ° μ λνλ¨
this.first = first;
this.last = last;
}
Person.prototype.getName = function () {
return this.first + " " + this.last;
};
// νλ‘ν νμ
class Person {
first: string;
last: string;
constructor(frist: string, last: string) {
this.first = first;
this.last = last;
}
getName() {
return this.first + " " + this.last;
}
}
const marie = new Person("Marie", "Curie");
const personName = marie.getName();
var λμ let/const μ¬μ©νκΈ°
- varλ₯Ό let, constλ‘ λ³κ²½ μ μΌλΆ μ½λμμ TS μ€λ₯κ° λ°μν μ μλλ°, μ€μ½ν λ¬Έμ κ° μκΈΈ μ μλ μ½λμ΄λ μμ νλ©΄ λλ€.
- μ€μ²© ν¨μ ꡬ문μλ varμ κ²½μ°μ λΉμ·ν μ€μ½ν λ¬Έμ κ° μ‘΄μ¬
- ν¨μ νΈμ΄μ€ν μ μ€ν μμλ₯Ό μμνκΈ° μ΄λ ΅κ² λ§λ€κ³ μ§κ΄μ μ΄μ§ μκΈ° λλ¬Έμ ν¨μ μ μΈμ λμ ννμμ μ°μλ μ견
for(;;) λμ for-of λλ λ°°μ΄ λ©μλ μ¬μ©νκΈ°
- C μ€νμΌμ for 루ν: for(;;)
- λͺ¨λ μλ°μ€ν¬λ¦½νΈμ for-of 루ν
- for-of 루νλ μ½λκ° μ§§κ³ μΈλ±μ€ λ³μλ₯Ό μ¬μ©νμ§λ μκΈ° λλ¬Έμ μ€μλ₯Ό μ€μΌ μ μμ΅λλ€.
- μΈλ±μ€ λ³μκ° νμνλ€? forEach λ©μλλ₯Ό μ¬μ©ν μ μμ΅λλ€.
ν¨μ ννμλ³΄λ€ νμ΄ν ν¨μλ₯Ό μ¬μ©νκΈ°
- μΌλ° ννμ ν¨μμ this λ°μΈλ©μ non-strict modeμμλ window, strict modeμμλ undefinedλ€.
- νμ΄ν ν¨μλ μ μλ νκ²½μ thisλ₯Ό μ μ§νλ€. == μΌκ΄λ this λ°μΈλ©. μ½λ°± ν¨μ λ΄μμ thisλ₯Ό μ¬μ©ν΄μΌ νλ κ²½μ°, νμ΄ν ν¨μλ₯Ό μ¬μ©νμ.
- noImplicitThisλ₯Ό μ€μ νλ©΄? this λ°μΈλ© κ΄λ ¨ μ€λ₯λ₯Ό νμν΄μ€λ€.
class Foo {
method() {
console.log(this);
[1, 2].forEach(function (i) {
console.log(this); // noImplicitThis μ€λ₯ λ°μ: 'this' implicitly has type 'any' because it does not have a type annotation.
});
}
arrow() {
console.log(this);
[1, 2].forEach((i) => {
console.log(this);
});
}
}
const f = new Foo();
f.method();
// strict λͺ¨λ: Foo, undefined, undefined
// non-strict λͺ¨λ: Foo, window, window
f.arrow();
// νμ Foo, Foo, Foo
λ¨μΆ κ°μ²΄ νν compact object literal κ³Ό ꡬ쑰 λΆν΄ ν λΉ object de-structuring μ¬μ©νκΈ°
{ x: x }
λ₯Ό{ x }
μ κ°μ΄ νν- κ°λ μ±μ΄ μ’κ³ μ€μκ° μ λ€.
- νμ΄ν ν¨μ λ΄μμ κ°μ²΄λ₯Ό λ°νν λλ μκ΄νΈλ‘ κ°μΈμΌ ν¨ => ν¨μμ ꡬνλΆμλ λΈλ‘μ΄λ λ¨μΌ ννμμ΄ νμνκΈ° λλ¬Έμ, μκ΄νΈλ‘ κ°μΈμ ννμμΌλ‘ λ§λλ κ²μ΄λ€.
["A", "B"].map((char, idx) => ({ char, idx }));
// [{char: "A", idx: 0}, {char: "B", idx: 1}]
- κ°μ²΄μ μμ± μ€ ν¨μλ₯Ό μΆμ½ν΄μ νννλ λ°©λ²
const obj = {
onClickLong: function (e) {
// ...
},
onClickCompact(e) {
// .. μΆμ½ νν!
},
};
- κ°μ²΄ ꡬ쑰 λΆν΄
const { props } = obj;
const { a, b } = props;
// μ΄λ κ² μ€μΌ κ²½μ° aμ bλ λ³μλ‘ μ μΈλμ§λ§, propsλ λ³μ μ μΈμ΄ μλμ μ£Όμ
const {
props: { a, b },
} = obj;
// ꡬ쑰 λΆν΄ λ¬Έλ² λ΄μμ κΈ°λ³Έκ°μ μ§μ ν μ μμ
const { a = "default" } = obj.props;
// ννμ²λΌ μ¬μ©νλ λ°°μ΄μμ μ μ©
const point = [1, 2, 3];
const [x, y, z] = point; // λ³μμ ν λΉ
const [, a, b] = point; // 첫 λ²μ§Έ μμλ 무μνλ κ²½μ°
// ν¨μ 맀κ°λ³μμλ μ¬μ©ν μ μμ΅λλ€
const points = [
[1, 2, 3],
[4, 5, 6],
];
points.forEach(([x, y, z]) => console.log(x + y + z)); // 6, 15
ν¨μ 맀κ°λ³μ κΈ°λ³Έκ° μ¬μ©νκΈ°
- μλ°μ€ν¬λ¦½νΈμμ ν¨μμ λͺ¨λ 맀κ°λ³μλ μ νμ μ΄λ©°, 맀κ°λ³μλ₯Ό μ§μ νμ§ μμΌλ©΄ undefinedλ‘ κ°μ£Όλ©λλ€.
function log2(a, b) {
console.log(a, b);
}
log2(); // undefined undefined
- 맀κ°λ³μμ κΈ°λ³Έκ°μ μ§μ νλ©΄ μ½λκ° κ°κ²°ν΄μ§ λΏλ§ μλλΌ, μ νμ 맀κ°λ³μλΌλ κ²μ λͺ νν λνλ΄λ ν¨κ³Όλ μ€ μ μμ΅λλ€. κΈ°λ³Έκ°μ κΈ°λ°μΌλ‘ νμ μΆλ‘ μ΄ κ°λ₯νκΈ° λλ¬Έμ, λ§μ΄κ·Έλ μ΄μ ν λ 맀κ°λ³μμ νμ ꡬ문μ μ°μ§ μμλ λ©λλ€.
// μλ λ°©μ
function paserNum(str, base) {
base = base || 10;
return parseInt(str, base);
}
// λͺ¨λ μλ°μ€ν¬λ¦½νΈ
function parseNum(str, base = 10) {
return parseInt(str, base);
}
μ μμ€ νλ‘λ―Έμ€λ μ½λ°± λμ async/await μ¬μ©νκΈ°
- asyncμ awaitμ μ¬μ©νλ©΄ μ½λκ° κ°κ²°ν΄μ Έμ λ²κ·Έλ μ€μλ₯Ό λ°©μ§ν μ μκ³ , λΉλκΈ° μ½λμ νμ μ λ³΄κ° μ λ¬λμ΄ νμ μΆλ‘ μ κ°λ₯νκ² ν©λλ€.
// callbackκ³Ό νλ‘λ―Έμ€
function getJSON(url: string) {
return fetch(url).then((response) => response.json());
}
function getJSONCallback(url: string, cb: (result: unknown) => void) {
// ...
}
// async/await
async function getJSON(url: string) {
const response = await fetch(url);
return response.json();
}
μ°κ΄ λ°°μ΄μ κ°μ²΄ λμ Mapκ³Ό Set μ¬μ©νκΈ°
function countWords(text: string) {
const counts: { [word: string]: number } = {};
for (const word of text.split(/[\s,.]+/)) {
counts[word] = 1 + (counts[word] || 0);
}
return counts;
}
- constructorμ μ΄κΈ°κ°μ Object.prototypeμ μλ μμ±μ ν¨μμ΄λ€.
- κ°μ²΄μ νλ‘ν νμ
체μΈμμ μμλ μμ±λ€μ΄ μμμΉ μμ λμμ μ λ°
- λ°©μ§νκΈ° μν΄ Mapμ μ¬μ©ν μ μλ€.
function countWordsMap(text: string) {
const counts = new Map<string, number>();
for (const word of text.split(/[\s,.]+/)) {
counts.set(word, 1 + (counts.get(word) || 0)); // κ°μ²΄μ ν€κ° λ¬Έμμ΄λ‘ μ ν
}
}
- κ²°κ³Ό
- Object.prototypeμ μμ±λ€κ³Ό μΆ©λν μνμ΄ μλ€. Mapμ μμλ₯Ό 보μ₯νκ³ , μ±λ₯ λ©΄μμλ λ ν¨μ¨μ
νμ μ€ν¬λ¦½νΈμ use strict λ£μ§ μκΈ°
- ES5μμλ λ²κ·Έκ° λ μ μλ μ½λ ν¨ν΄μ μ€λ₯λ₯Ό νμν΄μ£Όλ 'μ격 λͺ¨λ(strict mode)'κ° λμ
λ¨
- TSμ μμ μ± κ²μ¬ sanity checkκ° μ격 λͺ¨λλ³΄λ€ ν¨μ¬ μ격νλ€. (무μλ―Έ)
- alwaysStrict λλ strict μ΅μ μ μ€μ νλ©΄? μ격 λͺ¨λλ‘ μ½λλ₯Ό νμ±νκ³ , μμ±λ μλ°μ€ν¬λ¦½νΈμ 'use strict'μ μΆκ°ν©λλ€.
TC39, JS νμ€ν λ¨κ³
- TC39λ 맀λ μλ‘μ΄ κΈ°λ₯μ λ°ννκ³ μκ³ , μλ°μ€ν¬λ¦½νΈμ νμ€ν 4λ¨κ³ μ€ 3λ¨κ³ μ΄μμ κΈ°λ₯λ€μ νμ μ€ν¬λ¦½νΈ λ΄μ ꡬννκ³ μμ΅λλ€.
Stage 0: Strawman
μμ΄λμ΄κ° μ μλκ³ λ Όμλλ μ΄κΈ° λ¨κ³μ λλ€. μμ§ κ³΅μμ μΈ μ μμ΄ μλλ©°, μμ΄λμ΄ μμ€μμ λ Όμλ©λλ€.
Stage 1: Proposal
μ μμ΄ κ³΅μμ μΌλ‘ TC39μ μ μΆλκ³ , λͺ νν λ¬Έμ μ μμ μ루μ μ΄ ν¬ν¨λ©λλ€. μ μμ΄ λ°μ ν μ μλ ꡬ쑰λ₯Ό κ°μ§λ©°, νΌλλ°±μ λ°μ κ°μ λ©λλ€.
Stage 2: Draft
μ μμ΄ μ’ λ ꡬ체νλκ³ , ꡬ체μ μΈ λ¬Έμμ μμ κ° ν¬ν¨λ©λλ€. μ΄ λ¨κ³μμλ μ μμ΄ μ€μ λ‘ κ΅¬νλ κ°λ₯μ±μ΄ λμμ§λλ€. νμ μ€ν¬λ¦½νΈλ μ΄ λ¨κ³λΆν° μλ‘μ΄ κΈ°λ₯μ μ€νμ μΌλ‘ ꡬννκΈ° μμν μ μμ΅λλ€.
Stage 3: Candidate
μ μμ΄ κ±°μ μμ±λ μνλ‘, 리뷰μ νΌλλ°±μ ν΅ν΄ μ΅μ’ μ‘°μ μ΄ μ΄λ£¨μ΄μ§λλ€. μ΄ λ¨κ³μ μ μμ λλΆλΆμ κ²½μ° νμ€μΌλ‘ μ±νλ©λλ€. νμ μ€ν¬λ¦½νΈλ μ΄ λ¨κ³μ κΈ°λ₯μ μ κ·Ήμ μΌλ‘ ꡬννμ¬ μ¬μ©μμκ² μ 곡ν©λλ€.
Stage 4: Finished
μ μμ΄ μ΅μ’ μ μΌλ‘ μΉμΈλμ΄ νμ€μ ν¬ν¨λ©λλ€. μ΄ λ¨κ³μ κΈ°λ₯μ 곡μ ECMAScript μ¬μμ μΌλΆκ° λ©λλ€.
μμ½
- TS κ°λ° νκ²½μ λͺ¨λ μλ°μ€ν¬λ¦½νΈλ μ€νν μ μμΌλ―λ‘, μ΅μ κΈ°λ₯λ€μ μ κ·Ήμ μΌλ‘ μ¬μ©νλ€. μ½λ νμ§μ ν₯μμν¬ μ μκ³ νμ μ€ν¬λ¦½νΈμ νμ μΆλ‘ μ΄ λμμ§λ€.
- νμ μ€ν¬λ¦½νΈ κ°λ° νκ²½μμ μ»΄νμΌλ¬μ μΈμ΄ μλΉμ€λ₯Ό μ¬μ©ν΄ class, ꡬ쑰 λΆν΄, async/await κΈ°λ₯μ μ½κ² λ°°μΈ μ μλ€.
- 'use strict'λ νμ μ€ν¬λ¦½νΈ μ»΄νμΌλ¬ μμ€μμ μ¬μ©λλ―λ‘ μ½λμμ μ κ±°
- TC39 κΉν μ μ₯μ, νμ μ€ν¬λ¦½νΈμ λ¦΄λ¦¬μ€ λ ΈνΈλ₯Ό ν΅ν΄ μ΅μ κΈ°λ₯μ νμΈν μ μλ€.
μμ΄ν
59: νμ
μ€ν¬λ¦½νΈ λμ
μ μ @ts-check
μ JSDocμ μνν΄ λ³΄κΈ°
@ts-check
@ts-check
μ§μμλ₯Ό μ¬μ©νλ©΄, νμ μ€ν¬λ¦½νΈ μ νμμ μ΄λ€ λ¬Έμ κ° λ°μνλμ§ λ―Έλ¦¬ μνν΄ λ³Ό μ μμ΅λλ€.- νμ μ²΄μ»€κ° νμΌμ λΆμνκ³ , λ°κ²¬λ μ€λ₯λ₯Ό λ³΄κ³ νλλ‘ μ§μν¨ - λ§€μ° λμ¨ν μμ€μΌλ‘ νμ μ²΄ν¬ μννλλ°, noImplicitAny μ€μ μ ν΄μ ν κ²λ³΄λ€ 체ν¬λ₯Ό λ ν¨
type.d.ts: νλ‘μ νΈ νμ μ μΈ
- μ μΈλμ§ μμ μ μ λ³μ
// @ts-check
/// <reference path="./type.d.ts">
console.log(user.firstName);
// type.d.ts
interface UserData {
firstName: string;
lastName: string;
}
declare let user: UserData;
μλνν° λΌμ΄λΈλ¬λ¦¬
@ts-check
μ§μμλ₯Ό μ¬μ©νλ©΄μ, μλνν°μ λΌμ΄λΈλ¬λ¦¬μ νμ μ μΈμ μ€μΉ & νμ©ν΄μ νμ 체ν¬λ₯Ό μνν΄λ³Ό μ μλ€.
DOM μ리먼νΈμ JSDoc
- DOM μλ¦¬λ¨ΌνΈ κ΄λ ¨ μ€λ₯
- νμ λ¨μΈ, λ¦¬ν΄ νμ μ μ λ± TS κΈ°λ₯μ΄κΈ° λλ¬Έ
- JSDocμ μ¬μ©νμ¬ νμ λ¨μΈμ λ체ν μ μλ€.
// @ts-check
const ageEl = /** @type {HTMLInputElement} */ document.getElementById("age");
ageEl.value = "12";
λΆμ νν JSDoc
- μ΄λ―Έ JSDoc μ€νμΌμ μ£Όμμ μ¬μ© μ€μ΄μλ€λ©΄,
@ts-check
μ§μμλ₯Ό μ€μ νλ μκ°λΆν° κΈ°μ‘΄ μ£Όμμ νμ 체ν¬κ° λμνκ² λκ³ + μ€λ₯ λ°μ- μ€λ₯λ₯Ό νμΈνκ³ μμ
- Infer parameters types from usage
- JSμΌ λ
- TSμΌ λ
- μ λμνμ§ μλ κ²½μ°λ μκ³ , μ£Όμμ΄ μ½λ λΆλμ λλ €μ λ‘μ§μ ν΄μνλλ° λ°©ν΄κ° λ μ μμ΅λλ€.
- νμ μ€ν¬λ¦½νΈλ tsμμ κ°μ₯ μ λμνλ€. λ§μ΄κ·Έλ μ΄μ μ λͺ©ν => ts
- λ€λ§, μ΄λ―Έ JSDocs μ£ΌμμΌλ‘ νμ
μ λ³΄κ° λ§μ΄ λ΄κ²¨μλ μ½λλΌλ©΄?
@ts-check
μ§μμλ‘ νμ 체컀λ₯Ό μ€νν΄μ μ΄κΈ° μ€λ₯λ₯Ό λΉ λ₯΄κ² μ‘μ μ μλ€.
μμ½
- νμΌ μλ¨μ
// @ts-check
λ₯Ό μΆκ°νμ¬ μλ°μ€ν¬λ¦½νΈμμλ νμ 체ν¬λ₯Ό μνν μ μλ€. - μ μ μ μΈκ³Ό μλνν° λΌμ΄λΈλ¬λ¦¬μ νμ μ μΈμ μΆκ°νλ λ°©λ²μ μ΅ν μ μμ
- JSDoc μ£Όμμ μ νμ©νλ©΄? JSμμλ νμ λ¨μΈκ³Ό μΆλ‘ ν μ μμ
- JSDocμ μ€κ° λ¨κ³λ€.
μμ΄ν 60: allowJsλ‘ TSμ JS κ°μ΄ μ¬μ©νκΈ°
- allowJS μ΅μ
μ μ¬μ©νλ©΄, TSμ JSλ₯Ό μλ‘ importν μ μλ€.
- TSλ JSμ μμ μ§ν©μ΄λ€~
- λͺ¨λ λ¨μλ‘ νμ μ€ν¬λ¦½νΈλ‘ μ ννλ©΄μ, ν μ€νΈ μνν΄μΌνκΈ° λλ¬Έμ allowJs μ΅μ μ΄ νμ
- λ²λ€λ¬μ TSκ° ν΅ν©λμ΄ μκ±°λ, νλ¬κ·ΈμΈ λ°©μμΌλ‘ ν΅ν©μ΄ κ°λ₯νλ€λ©΄? allowJs κ°λ¨ν μ μ© κ°λ₯
- tsify, browserify
$ browserify index.ts -p [ tsify --allowJs ] > bundle.js
- jest.conifg.js
module.exports = { transform: { "^.+\\.tsx?$": "ts-jest", // μ λ¬ν νμ μ€ν¬λ¦½νΈ μμ€ μ§μ }, };
- outDir μ΅μ
- νμ μ€ν¬λ¦½νΈκ° outDirμ μ§μ λ λλ ν 리μ μμ€ Dirκ³Ό λΉμ·ν κ΅¬μ‘°λ‘ μλ°μ€ν¬λ¦½νΈ μ½λλ₯Ό μμ±νκ² λ¨ => outDirλ‘ μ§μ λ λλ ν 리λ₯Ό λμμΌλ‘ κΈ°μ‘΄ λΉλ 체μΈμ μ€ννλ©΄ λ¨
- κΈ°μ‘΄ μλ°μ€ν¬λ¦½νΈ κ·μΉ(target, module μ΅μ )μ λ°λΌ μΆλ ₯ μ΅μ μ μ‘°μ ν΄μΌ ν μ μμ
Things to Remember
- Use the allowJs compiler option to support mixed JavaScript and TypeScript as you transition your project.
- μ μ§μ λ§μ΄κ·Έλ μ΄μ μ μν΄, μλ°μ€ν¬λ¦½νΈμ νμ μ€ν¬λ¦½νΈλ₯Ό λμμ μ¬μ©ν μ μλ allowJs μ΅μ μ¬μ©
- Get your tests and build chain working with TypeScript before beginning large-scale migration.
- λκ·λͺ¨ λ§μ΄κ·Έλ μ΄μ μ μ, ν μ€νΈμ λΉλ 체μΈμ νμ μ€ν¬λ¦½νΈλ₯Ό μ μ©νλ€.
μμ΄ν 61: μμ‘΄μ± κ΄κ³μ λ°λΌ λͺ¨λ λ¨μλ‘ μ ννκΈ°
- μ μ§μ λ§μ΄κ·Έλ μ΄μ
- λͺ¨λ λ¨μλ‘ μ§ν
- λͺ¨λ κ° μμ‘΄μ± λ¬Έμ !
- λ€λ₯Έ λͺ¨λμ μμ‘΄νμ§ μλ μ΅νλ¨ λͺ¨λλΆν° μμ μ μμν΄μΌ νλ€.
- μλνν° λΌμ΄λΈλ¬λ¦¬
- νλ‘μ νΈ --μμ‘΄--> μλνν° λΌμ΄λΈλ¬λ¦¬
- μλνν° λΌμ΄λΈλ¬λ¦¬ --μμ‘΄x--> νλ‘μ νΈ
- μλνμ΄ λΌμ΄λΈλ¬λ¦¬ νμ μ 보λ₯Ό λ¨Όμ ν΄κ²°νλ€.
- μΈλΆ APIμ νμ
μ 보λ λ¨Όμ ν΄κ²°νλ€.
- μΈλΆ APIμ νμ μ 보λ λ¬Έλ§₯μ΄ μκΈ° λλ¬Έμ, νμ μ€ν¬λ¦½νΈκ° μΆλ‘ νκΈ° μ΄λ ΅λ€.
- API μ¬μμ κΈ°λ°μΌλ‘ νμ μ 보λ₯Ό μμ±ν΄μΌ νλ€.
μμ‘΄μ±
- dependency graphλ₯Ό κ·Έλ €λ³Ό μ μλ€.
- νμ΄ν: μμ‘΄μ±
- μ§μ μμ: μν μμ‘΄μ± circular dependency
- λλΆλΆμ νλ‘μ νΈμμ μμ‘΄μ± μ΅νλ¨μ μ νΈλ¦¬ν° λͺ¨λμ΄ μμΉνλ ν¨ν΄!
- λ§μ΄κ·Έλ μ΄μ
ν λλ? νμ
μ λ³΄λ§ μΆκ°νκ³ , 리ν©ν λ§μ νλ©΄ μλλ€.
- 리ν©ν λ§ μ¬νμ λͺ©λ‘ν νκΈ°
μ μΈλμ§ μμ ν΄λμ€ λ©€λ²
- ν΄λμ€ λ©€λ²λ₯Ό λͺ
μμ μΌλ‘ μ μΈνκΈ° μν΄μ, IDEμ quick fix κΈ°λ₯μ μ¬μ©ν μ μμ΅λλ€.
- Declare property '~~'
- Add all missing members
class Greeting {
constructor(name) {
this.greeting = "Hello";
// ~~~~~~~~ Property 'greeting' does not exist on type 'Greeting'
this.name = name;
// ~~~~ Property 'name' does not exist on type 'Greeting'
}
greet() {
return `${this.greeting} ${this.name}`;
// ~~~~~~~~ ~~~~ Property ... does not exist
}
}
- μλͺ»λ μ€κ³
- 리ν©ν λ§ νμ§ μμ΅λλ€!
- λ°κ²¬νλ©΄ κΈ°λ‘νκΈ°
νμ μ΄ λ°λλ κ°
- νκΊΌλ²μ κ°μ²΄λ₯Ό μμ±νκΈ°
// js => ts
const state = {};
state.name = "New York";
// ~~~~ Property 'name' does not exist on type '{}'
state.capital = "Albany";
// ~~~~~~~ Property 'capital' does not exist on type '{}'
// ts
const state = {
name: "New York",
capital: "Albany",
}; // OK
// μμλ°©νΈ λ¨μΈλ¬Έ
// λ§μ΄κ·Έλ μ΄μ
μ΄ μλ£λ μ΄ν, λ¬Έμ λ₯Ό μ λλ‘ ν΄κ²°ν΄μΌ νλ€!
interface State {
name: string;
capital: string;
}
const state = {} as State;
state.name = "New York"; // OK
state.capital = "Albany"; // OK
- JSDocκ³Ό
@ts-check
λ₯Ό μ¬μ©ν΄ νμ μ 보λ₯Ό μΆκ°ν μνλΌλ©΄, TSλ‘ μ ννλ μκ° νμ μ λ³΄κ° '무ν¨ν'λλ€λ κ²μ μ£Όμ (tsμμ λμνμ§ μμ)- Annotate with type from JSDoc
- JSDocμ μ¬μ©ν΄ νμ ꡬ문μ μμ±ν ν, JSDoc μμ !
- Annotate with type from JSDoc
- λ§μ§λ§ λ¨κ³: ν
μ€νΈ μ½λλ₯Ό νμ
μ€ν¬λ¦½νΈλ‘ μ ν
- ν μ€νΈ μ½λλ μμ‘΄μ± κ΄κ³λμ μ΅μλ¨μ μμΉ. λ§μ΄κ·Έλ μ΄μ μ λ§μ§λ§ λ¨κ³
Things to Remember
- Start migration by adding
@types
for third-party modules and external API calls.- λ§μ΄κ·Έλ μ΄μ μ μμ => μλνν° λͺ¨λκ³Ό μΈλΆ APIμ½
- Begin migrating your own modules from the bottom of the dependency graph upwards. The first module will usually be some sort of utility code. Consider visualizing the dependency graph to help you track progress.
- μμ‘΄μ± κ΄κ³λμ μλλΆν° μλ‘ μ¬λΌκ°λ©° λ§μ΄κ·Έλ μ΄μ νλ€. bottom to top~
- μ΅νλ¨μ λ³΄ν΅ μ νΈλ¦¬ν° μ½λλ€. μμ‘΄μ± κ΄κ³λλ₯Ό μκ°ννλ©΄μ μ§ν κ³Όμ μ μΆμ νλ κ²μ΄ μ’λ€.
- Resist the urge to refactor your code as you uncover odd designs. Keep a list of ideas for future refactors, but stay focused on TypeScript conversion.
- μ΄μν μ€κ³λ₯Ό λ°κ²¬ν΄λ 리ν©ν°λ§ κΈμ§. λ§μ΄κ·Έλ μ΄μ μ μ§μ€νλ€. 리ν©ν°λ§ μ¬λ£λ λͺ©λ‘μΌλ‘ λ§λ λ€.
- Be aware of common errors that come up during conversion. Move JSDoc types into TypeScript type annotations if necessary to avoid losing type safety as you convert.
- νμμ λ°λΌ JSDoc νμ μ νμ ꡬ문μΌλ‘ λ³κ²½νλ€. νμ μ€ν¬λ¦½νΈλ‘ μ ννλ©° λ°κ²¬νλ μΌλ°μ μ€λ₯λ₯Ό λμΉμ§ μλλ‘ νλ€.
μμ΄ν 62: λ§μ΄κ·Έλ μ΄μ μ μμ±μ μν΄ noImplicitAny μ€μ νκΈ°
- noImplicitAnyλ₯Ό μ€μ νμ¬ λ§μ΄κ·Έλ μ΄μ
μλ£
- μ²μμλ λ‘컬μλ§ μ΅μ μ€μ νκ³ μμ (μ격μ μ€μ νμ§ μμΌλ©΄ λΉλ μ€ν¨κ° μλ¨κΈ° λλ¬Έ)
- μμ ν λΆλΆλ§ 컀λ°ν΄μ μ μ§μ λ§μ΄κ·Έλ μ΄μ νκΈ°!
- νμ μ²΄μ»€κ° λ°μνλ μ€λ₯μ κ°μ => noImplicitAnyμ κ΄λ ¨λ μμ μ μ§μ²μ λνλ΄λ μ§νλ‘ νμ©
- νμ
체ν¬μ κ°λ μμν λμ΄κΈ°
- strictNullChecks => noImplicitAny => strict
Things to Remember
- Don't consider your TypeScript migration done until you adopt noImplicitAny. Loose type checking can mask real mistakes in type declarations.
- noImplictAny μ€μ μ νμ±ννμ¬ λ§μ΄κ·Έλ μ΄μ μ λ§μ§λ§ λ¨κ³λ₯Ό μ§ννλ€.
- noImplictAny μ€μ μ΄ μλ€λ©΄? νμ μ μΈκ³Ό κ΄λ ¨λ μ€μ μ€λ₯κ° λλ¬λμ§ μλλ€.
- Fix type errors gradually before enforcing noImplicitAny. Give your team a chance to get comfortable with TypeScript before adopting stricter checks.
- noImplictAnyλ₯Ό μ λ©΄ μ μ©νκΈ° μ μ, νμ μ€λ₯λ₯Ό μ μ§μ μΌλ‘ μμ νλ€.
- μ격ν νμ 체ν¬λ₯Ό μ μ©νκΈ° μ μ νμλ€μ΄ νμ μ€ν¬λ¦½νΈμ μ΅μν΄μ§ μ μλλ‘ νλ€.