Recognize the Limits of Excess Property Checking
- νμ μ΄ λͺ μλ λ³μμ κ°μ²΄ 리ν°λ΄μ ν λΉν λ νμ μ€ν¬λ¦½νΈλ ν΄λΉ νμ μ μμ±μ΄ μλμ§ βκ·Έ μΈμ μμ±μ μλμ§β νμΈ
interface Room {
numDoors: number;
ceilingHeightFt: number;
}
const r1: Room = {
numDoors: 1,
ceilingHeightFt: 10,
elephant: 'present',
// ~~~~~~~~~~~~~~~~~~ Object literal may only specify known properties,
// and 'elephant' does not exist in type 'Room'
};
const obj = {
numDoors: 1,
ceilingHeightFt: 10,
elephant: 'present',
};
const r2: Room = obj; // OK
- r1μ κ²½μ°. Room μΈν°νμ΄μ€μ μ μΈλμ§ μμ μμ±μ΄ μΆκ°λμμ λ, βꡬ쑰μ νμ΄νβ κ΄μ μμ 보면 μ€λ₯κ° λ°μνμ§ μμμΌ νμ§λ§ λ°μ.
- obj κ°μ²΄μμ μΆλ‘ λ νμ μ Room νμ (μ λΆλΆ μ§ν©)μ ν¬ν¨νλ―λ‘ Room νμ μ ν λΉ κ°λ₯νλ©°, νμ 체컀λ ν΅κ³Ό
- r1 μμλ
μμ¬ μμ± μ²΄ν¬
λΌλ κ³Όμ μ΄ μν - μμ¬ μμ± μ²΄ν¬λ
- 쑰건μ λ°λΌ λμνμ§ μμ
- ν΅μμ μΈ ν λΉ κ°λ₯ κ²μ¬μ ν¨κΌ μ°μ΄λ©΄ ꡬ쑰μ νμ΄νμ΄ λ¬΄μμΈμ§ ν·κ°λ¦Ό
- ν λΉ κ°λ₯ κ²μ¬μλ λ³λμ κ³Όμ
interface Options {
title: string;
darkMode?: boolean;
}
function createWindow(options: Options) {
if (options.darkMode) {
// setDarkMode();
}
// ...
}
createWindow({
title: 'Spider Solitaire',
darkmode: true
// ~~~~~~~~~~~~~ Object literal may only specify known properties, but
// 'darkmode' does not exist in type 'Options'.
// Did you mean to write 'darkMode'?
});
const o1: Options = document; // OK
const o2: Options = new HTMLAnchorElement; // OK
- μ μ½λλ λ°νμ μ€λ₯λ μμΌλ νμ μ€ν¬λ¦½νΈ μ€λ₯λ§ λ°μ.
- Options νμ μ κ²½μ°, μ΄λ€ κ°μ²΄κ° title μμ±(string νμ )μ κ°μ§κ³ μλ€λ©΄ - λ¨, darkMode κ°μ΄ μκ±°λ boolean νμ μ΄μ΄μΌ ν¨ - κ·Έ κ°μ²΄λ λͺ¨λ Options νμ λ²μμ μν¨.
- κ·Έλμ o1, o2 λ title μμ±(string νμ )μ κ°μ§κ³ μμ΄μ μ μ λμ.
μμ¬ μμ± μ²΄ν¬
λ₯Ό μ΄μ©νλ©΄, κ°μ²΄ 리ν°λ΄μ μ μ μλ μμ±μ νμ©νμ§ μμμΌλ‘μ¨ λ¬Έμ μ μ λ°©μ§- so,
μ격ν κ°μ²΄ 리ν°λ΄ 체ν¬
λΌκ³ λΆλ¦¬κΈ°λ
- so,
document, new HTMLAnchorElement
λ κ°μ²΄ 리ν°λ΄μ΄ μλκΈ° λλ¬Έμ μμ¬ μμ± μ²΄ν¬ μλ¨{ title, darkmode }
κ°μ²΄λ μμ¬ μμ± μ²΄ν¬ κ°λ₯
const o1: Options = { darkmode: true, title: 'Ski Free' };
// ~~~~~~~~ 'darkmode' does not exist in type 'Options'...
const intermediate = { darkmode: true, title: 'Ski Free' };
const o2: Options = intermediate; // OK
const o3 = { darkmode: true, title: 'Ski Free' } as Options; // OK
- o1 μ μ€λ₯Έμͺ½μ κ°μ²΄ 리ν°λ΄, o2 μ μ€λ₯Έμͺ½μ κ°μ²΄ 리ν°λ΄μ΄ μλ. κ·Έλμ μμ¬ μμ± μ²΄ν¬κ° μ μ©λμ§ μμ.
- μμ¬ μμ± μ²΄ν¬λ νμ
λ¨μΈλ¬Έμ μ¬μ©ν λμλ μ μ©λμ§ μμ - o3
- κ·Έλμ νμ λ¨μΈλ¬Έλ³΄λ€ μ μΈλ¬Έμ μ¬μ©ν΄μΌ νλ€!
interface Options {
darkMode?: boolean;
[otherOptions: string]: unknown;
}
const o: Options = { darkmode: true }; // OK
- μμ¬ μμ± μ²΄ν¬λ₯Ό μνμ§ μμΌλ©΄,
μΈλ±μ€ μκ·Έλμ²
λ₯Ό μ¬μ©ν΄ νμ μ€ν¬λ¦½νΈκ° μΆκ°μ μΈ μμ±μ μμνλλ‘ ν¨
interface LineChartOptions {
logscale?: boolean;
invertedYAxis?: boolean;
areaChart?: boolean;
}
const opts = { logScale: true };
const o: LineChartOptions = opts;
// ~ Type '{ logScale: boolean; }' has no properties in common
// with type 'LineChartOptions'
-
μ νμ μμ±λ§ κ°μ§λ
μ½ν(weak)
νμ μλ λΉμ·ν 체ν¬κ° λμ -
ꡬ쑰μ κ΄μ μμ
LineChartOptions
νμ μ λͺ¨λ κ°μ²΄λ₯Ό ν¬ν¨ν μ μμ -
μ΄λ° μ½ν νμ μ νμ μ€ν¬λ¦½νΈκ° κ° νμ κ³Ό μ μΈ νμ μ 곡ν΅λ μμ±μ΄ μλμ§ λ³λλ‘ νμΈ
-
κ³΅ν΅ μμ± μ²΄ν¬
λμμ¬ μμ± μ²΄ν¬
μ λΉμ·νκ² μ€νλ₯Ό μ‘λλ° ν¨κ³Όμ , ꡬ쑰μ μΌλ‘ μ격νμ§ μμ -
μμ¬ μμ± μ²΄ν¬μ λ€λ₯Έ μ μ μ½ν νμ κ³Ό κ΄λ ¨λ ν λΉλ¬Έλ§λ€ μν. μμ λ³μλ₯Ό μ κ±°ν΄λ κ³΅ν΅ μμ± μ²΄ν¬λ λμν¨
-
μμ¬ μμ± μ²΄ν¬λ
- ꡬ쑰μ νμ΄ν μμ€ν μμ νμ©λλ μ€μλ₯Ό μ€μ¬μ€
- μ νμ νλλ₯Ό ν¬ν¨νλ νμ μ νΉν μ μ©
- μ μ© λ²μκ° μ νμ , μ€μ§ κ°μ²΄ 리ν°λ΄μλ§ μ μ©
Apply Types to Entire Function Expressions When Possible
- js, ts μμλ
ν¨μ λ¬Έμ₯(statement)
κ³Όν¨μ ννμ(expression)
μ λ€λ₯΄κ² μΈμ
function rollDice1(sides: number): number { /* COMPRESS */ return 0; /* END */ } // Statement
const rollDice2 = function(sides: number): number { /* COMPRESS */ return 0; /* END */ }; // Expression
const rollDice3 = (sides: number): number => { /* COMPRESS */ return 0; /* END */ }; // Also expression
-
νμ μ€ν¬λ¦½νΈμμλ ν¨μ ννμμ μ¬μ©νλ κ²μ΄ μ’λ€.
β ν¨μμ 맀κ°λ³μλΆν° λ°νκ°κΉμ§ μ 체λ₯Ό ν¨μ νμ μΌλ‘ μ μΈ, ν¨μ ννμμ μ¬μ¬μ© κ°λ₯
type DiceRollFn = (sides: number) => number;
const rollDice: DiceRollFn = sides => { /* COMPRESS */ return 0; /* END */ };
// μ¬κΈ°μμ tsκ° μ΄λ―Έ sidesμ νμ
μ numberλ‘ μΈμ
- ν¨μ νμ μ μΈμ μ₯μ : λΆνμν μ½λμ λ°λ³΅ μ€μ
function add(a: number, b: number) { return a + b; }
function sub(a: number, b: number) { return a - b; }
function mul(a: number, b: number) { return a * b; }
function div(a: number, b: number) { return a / b; }
// λ°λ³΅λλ ν¨μ μκ·Έλμ²λ₯Ό νλμ ν¨μ νμ
μΌλ‘ ν΅ν©
type BinaryFn = (a: number, b: number) => number;
const add: BinaryFn = (a, b) => a + b;
const sub: BinaryFn = (a, b) => a - b;
const mul: BinaryFn = (a, b) => a * b;
const div: BinaryFn = (a, b) => a / b;
-
λΌμ΄λΈλ¬λ¦¬λ κ³΅ν΅ ν¨μ μκ·Έλμ²λ₯Ό νμ μΌλ‘ μ 곡νκΈ°λ
- ex) 리μ‘νΈλ
MouseEvent
(ν¨μμ 맀κ°λ³μμ λͺ μ) νμ λμ , ν¨μ μ 체μ μ μ©ν μ μλMouseEventHandler
νμ μ 곡
- ex) 리μ‘νΈλ
-
μκ·Έλμ²κ° μΌμΉνλ λ€λ₯Έ ν¨μκ° μμ λλ ν¨μ ννμμ νμ μ μ© κ°λ₯
- λ€λ₯Έ ν¨μμ μκ·Έλμ²λ₯Ό μ°Έμ‘°νλ €λ©΄
typeof fn
μ¬μ©
- λ€λ₯Έ ν¨μμ μκ·Έλμ²λ₯Ό μ°Έμ‘°νλ €λ©΄
declare function fetch(
input: RequestInfo, init?: RequestInit
): Promise<Response>;
async function checkedFetch(input: RequestInfo, init?: RequestInit) {
const response = await fetch(input, init);
if (!response.ok) {
// Converted to a rejected Promise in an async function
throw new Error('Request failed: ' + response.status);
}
return response;
}
// ν¨μμ 맀κ°λ³μμ λ¦¬ν΄ νμ
κΉμ§ 보μ₯
const checkedFetch: typeof fetch = async (input, init) => {
const response = await fetch(input, init);
if (!response.ok) {
throw new Error('Request failed: ' + response.status);
}
return response;
}
// μ€μλ‘ errorλ₯Ό return νμ κ²½μ°μλ ν¨μ νμ
μ μΈ λλΆμ μ€λ₯λ₯Ό κ°μ§
// ν¨μ ννμμ΄ μλλΌ ν¨μ λ¬Έμ₯ ννμΈ κ²½μ°, checkedFetch ꡬν체μ μ€λ₯κ° λ°μνλκ² μλ μ΄ ν¨μλ₯Ό νΈμΆν μμΉμμ λ°μ
const checkedFetch: typeof fetch = async (input, init) => {
// ~~~~~~~~~~~~ Type 'Promise<Response | HTTPError>'
// is not assignable to type 'Promise<Response>'
// Type 'Response | HTTPError' is not assignable
// to type 'Response'
const response = await fetch(input, init);
if (!response.ok) {
return new Error('Request failed: ' + response.status);
}
return response;
}
Know the Differences Between type and interface
- νμ μ€ν¬λ¦½νΈμμ λͺ λͺ λ νμ (named type)μ μ μνλ λ°©λ² : λλΆλΆμ κ²½μ° λ μ€ μ무거λ μ¬μ©ν΄λ λ¨
// νμ
type TState = {
name: string;
capital: string;
}
// μΈν°νμ΄μ€
interface IState {
name: string;
capital: string;
}
// νμ
κ³Ό μΈν°νμ΄μ€ μμ T/I λΆμ΄μ§ λ§κ²
- μΈν°νμ΄μ€ λμ ν΄λμ€ μ¬μ© κ°λ₯. κ·Έλ¬λ ν΄λμ€λ κ°μΌλ‘λ μ¬μ©λλ js λ°νμ κ°λ
-
λ μ€ μ΄λ κ²μΌλ‘ νμ μ μ μνλ μνμλ μ°¨μ΄κ° μμ
// μΆκ° μμ±μ ν¨κ» ν λΉνλ©΄ νμ , μΈν°νμ΄μ€ μ μΈ λ λ€ λμΌν μ€λ₯ λ°μ const wyoming: TState = { name: 'Wyoming', capital: 'Cheyenne', population: 500_000 // ~~~~~~~~~~~~~~~~~~ Type ... is not assignable to type 'TState' // Object literal may only specify known properties, and // 'population' does not exist in type 'TState' };
-
μΈλ±μ€ μκ·Έλμ² μ¬μ© κ°λ₯
type TDict = { [key: string]: string }; interface IDict { [key: string]: string; }
-
ν¨μ νμ λ μ μ κ°λ₯
type TFn = (x: number) => string; interface IFn { (x: number): string; } const toStrT: TFn = x => '' + x; // OK const toStrI: IFn = x => '' + x; // OK // ν¨μ νμ μ μΆκ°μ μΈ μμ±μ΄ μλ κ²½μ° type TFnWithProperties = { (x: number): number; // '=>' μ΄μ©ν΄ ν¨μλ₯Ό μ μν μλ μμ. λ΄μ©μ μ°¨μ΄λ μλ€ prop: string; } interface IFnWithProperties { (x: number): number; prop: string; } // μ¬κΈ° μ λͺ¨λ₯΄κ² μ. ν¨μ μ μλ₯Ό μ΄λ κ²λ νλ
β λ¨μν ν¨μ νμ μ νμ λ³μΉ(alias) μ΄ λ λμ μ ν. μΆκ° μμ±μ΄ μλ κ²½μ° λ λ€ μ°¨μ΄ μμ
-
μ λλ¦ μ¬μ© κ°λ₯
type TPair<T> = { first: T; second: T; } interface IPair<T> { first: T; second: T; }
-
μΈν°νμ΄μ€ - νμ νμ₯ κ°λ₯ νμ - μΈν°νμ΄μ€ νμ₯ κ°λ₯
interface IStateWithPop extends TState { population: number; } type TStateWithPop = IState & { population: number; };
βΒ μΈν°νμ΄μ€λ μ λμ¨ νμ κ°μ 볡μ‘ν νμ μ νμ₯ λΆκ°
β 볡μ‘ν νμ μ νμ₯νκ³ μΆμΌλ©΄ νμ κ³Ό & μ¬μ©
-
ν΄λμ€ κ΅¬ν(implements)ν λ μ¬μ© κ°λ₯
class StateT implements TState { name: string = ''; capital: string = ''; } class StateI implements IState { name: string = ''; capital: string = ''; }
-
μ λμ¨ νμ μ μμ§λ§ μ λμ¨ μΈν°νμ΄μ€λ μμ
type AorB = 'a' | 'b';
-
μΈν°νμ΄μ€λ νμ μ νμ₯ν μ μμ§λ§ μ λμ¨μ ν μ μμ.
// μ λμ¨ νμ μ νμ₯νλκ² νμν κ²½μ°. // νμ μ νλμ λ³μλͺ μΌλ‘ 맀ννμ¬ μΈν°νμ΄μ€ μ μνλ μμ type Input = { /* ... */ }; type Output = { /* ... */ }; interface VariableMap { [name: string]: Input | Output; } // μ λμ¨ νμ μ name μμ±μ λΆμΈ νμ μ λ§λ€μλ type NamedVariable = (Input | Output) & { name: string };
β μ΄ νμ μ μΈν°νμ΄μ€λ‘ νν λΆκ°
β μΌλ°μ μΌλ‘ type ν€μλλ interface λ³΄λ€ μ°μμκ° λ§λ€.
-
ννκ³Ό λ°°μ΄ νμ λ type ν€μλ μ΄μ©ν΄ λ κ°κ²°νκ² νν κ°λ₯
type Pair = [number, number]; type StringList = string[]; type NamedNums = [string, ...number[]]; // μΈν°νμ΄μ€λ‘ νν λΉμ€λ―λ νκ² κ΅¬νν κ²½μ° // ννμμ μ¬μ©ν μ μλ concat κ°μ λ©μλ μ¬μ© λΆκ° interface Tuple { 0: number; 1: number; length: 2; } const t: Tuple = [10, 20]; // OK
-
μΈν°νμ΄μ€λ
보κ°(augment)
μ΄ κ°λ₯interface IState { name: string; capital: string; } interface IState { population: number; } const wyoming: IState = { name: 'Wyoming', capital: 'Cheyenne', population: 500_000 }; // OK
-
μ΄ μ²λΌ μμ±μ νμ₯νλ κ² β μ μΈ λ³ν©(declaration merging)
-
μ μΈ λ³ν©μ μ£Όλ‘ νμ μ μΈ νμΌμμ μ¬μ©
β νμ μ μΈ νμΌμ μμ±ν λλ μ μΈ λ³ν©μ μ§μνκΈ° μν΄ λ°λμ μΈν°νμ΄μ€λ₯Ό μ¬μ©ν΄μΌνκ³ , νμ€μ λ°λΌμΌ ν¨
-
λ³ν©μ μ μΈμ²λΌ μΌλ°μ μΈ μ½λμμλ μ§μ
-
νμ μ κΈ°μ‘΄ νμ μ μΆκ°μ μΈ λ³΄κ°μ΄ μλ κ²½μ°μλ§ μ¬μ©ν΄μΌν¨
-
-
κ²°λ‘
- 볡μ‘ν νμ μ΄λ©΄ νμ λ³μΉ μ¬μ©
- κ°λ¨ν κ°μ²΄ νμ
μ΄λ©΄
- μΌκ΄μ±μ κ΄μ : μΌκ΄λκ² μΈν°νμ΄μ€λ₯Ό μ¬μ©νλ νλ‘μ νΈμμ μΈν°νμ΄μ€, μΌκ΄λκ² νμ μ μ¬μ©νλ κ²½μ°μ νμ
- 보κ°μ κ΄μ : ν₯ν νμ μ μΈμ 보κ°μ κ°λ₯μ±μ΄ μλ€λ©΄ μΈν°νμ΄μ€ μΆμ²
- νλ‘μ νΈ λ΄λΆμ μΌλ‘ μ¬μ©λλ νμ μ μ μΈ λ³ν©μ΄ λ°μνλ κ²μ μλͺ»λ μ€κ³ β νμ μ μ¬μ©ν΄μΌ ν¨