Skip to content

Latest commit

ย 

History

History
579 lines (442 loc) ยท 22.6 KB

interfaces.md

File metadata and controls

579 lines (442 loc) ยท 22.6 KB

์†Œ๊ฐœ (Introduction)

TypeScript์˜ ํ•ต์‹ฌ ์›์น™ ์ค‘ ํ•˜๋‚˜๋Š” ํƒ€์ž… ๊ฒ€์‚ฌ๊ฐ€ ๊ฐ’์˜ ํ˜•ํƒœ์— ์ดˆ์ ์„ ๋งž์ถ”๊ณ  ์žˆ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ด๋ฅผ "๋• ํƒ€์ดํ•‘(duck typing)" ํ˜น์€ "๊ตฌ์กฐ์  ์„œ๋ธŒํƒ€์ดํ•‘ (structural subtyping)"์ด๋ผ๊ณ ๋„ ํ•ฉ๋‹ˆ๋‹ค. TypeScript์—์„œ, ์ธํ„ฐํŽ˜์ด์Šค๋Š” ์ด๋Ÿฐ ํƒ€์ž…๋“ค์˜ ์ด๋ฆ„์„ ์ง“๋Š” ์—ญํ• ์„ ํ•˜๊ณ  ์ฝ”๋“œ ์•ˆ์˜ ๊ณ„์•ฝ์„ ์ •์˜ํ•˜๋Š” ๊ฒƒ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ํ”„๋กœ์ ํŠธ ์™ธ๋ถ€์—์„œ ์‚ฌ์šฉํ•˜๋Š” ์ฝ”๋“œ์˜ ๊ณ„์•ฝ์„ ์ •์˜ํ•˜๋Š” ๊ฐ•๋ ฅํ•œ ๋ฐฉ๋ฒ•์ž…๋‹ˆ๋‹ค.

์ฒซ ๋ฒˆ์งธ ์ธํ„ฐํŽ˜์ด์Šค (Our First Interface)

์–ด๋–ป๊ฒŒ ์ธํ„ฐํŽ˜์ด์Šค๊ฐ€ ๋™์ž‘ํ•˜๋Š”์ง€ ํ™•์ธํ•˜๋Š” ๊ฐ€์žฅ ์‰ฌ์šด ๋ฐฉ๋ฒ•์€ ๊ฐ„๋‹จํ•œ ์˜ˆ์ œ๋กœ ์‹œ์ž‘ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค:

function printLabel(labeledObj: { label: string }) {
    console.log(labeledObj.label);
}

let myObj = {size: 10, label: "Size 10 Object"};
printLabel(myObj);

ํƒ€์ž… ๊ฒ€์‚ฌ๋Š” printLabel ํ˜ธ์ถœ์„ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค. printLabel ํ•จ์ˆ˜๋Š” string ํƒ€์ž… label์„ ๊ฐ–๋Š” ๊ฐ์ฒด๋ฅผ ํ•˜๋‚˜์˜ ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ๊ฐ€์ง‘๋‹ˆ๋‹ค. ์ด ๊ฐ์ฒด๊ฐ€ ์‹ค์ œ๋กœ๋Š” ๋” ๋งŽ์€ ํ”„๋กœํผํ‹ฐ๋ฅผ ๊ฐ–๊ณ  ์žˆ์ง€๋งŒ, ์ปดํŒŒ์ผ๋Ÿฌ๋Š” ์ตœ์†Œํ•œ ํ•„์š”ํ•œ ํ”„๋กœํผํ‹ฐ๊ฐ€ ์žˆ๋Š”์ง€์™€ ํƒ€์ž…์ด ์ž˜ ๋งž๋Š”์ง€๋งŒ ๊ฒ€์‚ฌํ•ฉ๋‹ˆ๋‹ค. TypeScript๊ฐ€ ๊ด€๋Œ€ํ•˜์ง€ ์•Š์€ ๋ช‡ ๊ฐ€์ง€ ๊ฒฝ์šฐ๋Š” ๋‚˜์ค‘์— ๋‹ค๋ฃจ๊ฒ ์Šต๋‹ˆ๋‹ค.

์ด๋ฒˆ์—” ๊ฐ™์€ ์˜ˆ์ œ๋ฅผ, ๋ฌธ์ž์—ด ํƒ€์ž…์˜ ํ”„๋กœํผํ‹ฐ label์„ ๊ฐ€์ง„ ์ธํ„ฐํŽ˜์ด์Šค๋กœ ๋‹ค์‹œ ์ž‘์„ฑํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค:

interface LabeledValue {
    label: string;
}

function printLabel(labeledObj: LabeledValue) {
    console.log(labeledObj.label);
}

let myObj = {size: 10, label: "Size 10 Object"};
printLabel(myObj);

LabeledValue ์ธํ„ฐํŽ˜์ด์Šค๋Š” ์ด์ „ ์˜ˆ์ œ์˜ ์š”๊ตฌ์‚ฌํ•ญ์„ ๋˜‘๊ฐ™์ด ๊ธฐ์ˆ ํ•˜๋Š” ์ด๋ฆ„์œผ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ์ธํ„ฐํŽ˜์ด์Šค๋Š” ์—ฌ์ „ํžˆ ๋ฌธ์ž์—ด ํƒ€์ž…์˜ label ํ”„๋กœํผํ‹ฐ ํ•˜๋‚˜๋ฅผ ๊ฐ€์ง„๋‹ค๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค. ๋‹ค๋ฅธ ์–ธ์–ด์ฒ˜๋Ÿผ printLabel์— ์ „๋‹ฌํ•œ ๊ฐ์ฒด๊ฐ€ ์ด ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ตฌํ˜„ํ•ด์•ผ ํ•œ๋‹ค๊ณ  ๋ช…์‹œ์ ์œผ๋กœ ์–˜๊ธฐํ•  ํ•„์š”๋Š” ์—†์Šต๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์„œ ์ค‘์š”ํ•œ ๊ฒƒ์€ ํ˜•ํƒœ๋ฟ์ž…๋‹ˆ๋‹ค. ํ•จ์ˆ˜์— ์ „๋‹ฌ๋œ ๊ฐ์ฒด๊ฐ€ ๋‚˜์—ด๋œ ์š”๊ตฌ ์กฐ๊ฑด์„ ์ถฉ์กฑํ•˜๋ฉด, ํ—ˆ์šฉ๋ฉ๋‹ˆ๋‹ค.

ํƒ€์ž… ๊ฒ€์‚ฌ๋Š” ํ”„๋กœํผํ‹ฐ๋“ค์˜ ์ˆœ์„œ๋ฅผ ์š”๊ตฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋‹จ์ง€ ์ธํ„ฐํŽ˜์ด์Šค๊ฐ€ ์š”๊ตฌํ•˜๋Š” ํ”„๋กœํผํ‹ฐ๋“ค์ด ์กด์žฌํ•˜๋Š”์ง€์™€ ํ”„๋กœํผํ‹ฐ๋“ค์ด ์š”๊ตฌํ•˜๋Š” ํƒ€์ž…์„ ๊ฐ€์กŒ๋Š”์ง€๋งŒ์„ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค.

์„ ํƒ์  ํ”„๋กœํผํ‹ฐ (Optional Properties)

์ธํ„ฐํŽ˜์ด์Šค์˜ ๋ชจ๋“  ํ”„๋กœํผํ‹ฐ๊ฐ€ ํ•„์š”ํ•œ ๊ฒƒ์€ ์•„๋‹™๋‹ˆ๋‹ค. ์–ด๋–ค ์กฐ๊ฑด์—์„œ๋งŒ ์กด์žฌํ•˜๊ฑฐ๋‚˜ ์•„์˜ˆ ์—†์„ ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค. ์„ ํƒ์  ํ”„๋กœํผํ‹ฐ๋“ค์€ ๊ฐ์ฒด ์•ˆ์˜ ๋ช‡ ๊ฐœ์˜ ํ”„๋กœํผํ‹ฐ๋งŒ ์ฑ„์›Œ ํ•จ์ˆ˜์— ์ „๋‹ฌํ•˜๋Š” "option bags" ๊ฐ™์€ ํŒจํ„ด์„ ๋งŒ๋“ค ๋•Œ ์œ ์šฉํ•ฉ๋‹ˆ๋‹ค.

์ด ํŒจํ„ด์˜ ์˜ˆ์ œ๋ฅผ ํ•œ๋ฒˆ ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค:

interface SquareConfig {
    color?: string;
    width?: number;
}

function createSquare(config: SquareConfig): {color: string; area: number} {
    let newSquare = {color: "white", area: 100};
    if (config.color) {
        newSquare.color = config.color;
    }
    if (config.width) {
        newSquare.area = config.width * config.width;
    }
    return newSquare;
}

let mySquare = createSquare({color: "black"});

์„ ํƒ์  ํ”„๋กœํผํ‹ฐ๋ฅผ ๊ฐ€์ง€๋Š” ์ธํ„ฐํŽ˜์ด์Šค๋Š” ๋‹ค๋ฅธ ์ธํ„ฐํŽ˜์ด์Šค์™€ ๋น„์Šทํ•˜๊ฒŒ ์ž‘์„ฑ๋˜๊ณ , ์„ ํƒ์  ํ”„๋กœํผํ‹ฐ๋Š” ์„ ์–ธ์—์„œ ํ”„๋กœํผํ‹ฐ ์ด๋ฆ„ ๋์— ?๋ฅผ ๋ถ™์—ฌ ํ‘œ์‹œํ•ฉ๋‹ˆ๋‹ค.

์„ ํƒ์  ํ”„๋กœํผํ‹ฐ์˜ ์ด์ ์€ ์ธํ„ฐํŽ˜์ด์Šค์— ์†ํ•˜์ง€ ์•Š๋Š” ํ”„๋กœํผํ‹ฐ์˜ ์‚ฌ์šฉ์„ ๋ฐฉ์ง€ํ•˜๋ฉด์„œ, ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ์†์„ฑ์„ ๊ธฐ์ˆ ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, createSquare์•ˆ์˜ color ํ”„๋กœํผํ‹ฐ ์ด๋ฆ„์„ ์ž˜๋ชป ์ž…๋ ฅํ•˜๋ฉด, ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€๋กœ ์•Œ๋ ค์ค๋‹ˆ๋‹ค:

interface SquareConfig {
    color?: string;
    width?: number;
}

function createSquare(config: SquareConfig): { color: string; area: number } {
    let newSquare = {color: "white", area: 100};
    if (config.clor) {
        // Error: Property 'clor' does not exist on type 'SquareConfig'
        newSquare.color = config.clor;
    }
    if (config.width) {
        newSquare.area = config.width * config.width;
    }
    return newSquare;
}

let mySquare = createSquare({color: "black"});

์ฝ๊ธฐ์ „์šฉ ํ”„๋กœํผํ‹ฐ (Readonly properties)

์ผ๋ถ€ ํ”„๋กœํผํ‹ฐ๋“ค์€ ๊ฐ์ฒด๊ฐ€ ์ฒ˜์Œ ์ƒ์„ฑ๋  ๋•Œ๋งŒ ์ˆ˜์ • ๊ฐ€๋Šฅํ•ด์•ผํ•ฉ๋‹ˆ๋‹ค. ํ”„๋กœํผํ‹ฐ ์ด๋ฆ„ ์•ž์— readonly๋ฅผ ๋„ฃ์–ด์„œ ์ด๋ฅผ ์ง€์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

interface Point {
    readonly x: number;
    readonly y: number;
}

๊ฐ์ฒด ๋ฆฌํ„ฐ๋Ÿด์„ ํ• ๋‹นํ•˜์—ฌ Point๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค. ํ• ๋‹น ํ›„์—๋Š” x, y๋ฅผ ์ˆ˜์ •ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

let p1: Point = { x: 10, y: 20 };
p1.x = 5; // ์˜ค๋ฅ˜!

TypeScript์—์„œ๋Š” ๋ชจ๋“  ๋ณ€๊ฒฝ ๋ฉ”์„œ๋“œ(Mutating Methods)๊ฐ€ ์ œ๊ฑฐ๋œ Array<T>์™€ ๋™์ผํ•œ ReadonlyArray<T> ํƒ€์ž…์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ ์ƒ์„ฑ ํ›„์— ๋ฐฐ์—ด์„ ๋ณ€๊ฒฝํ•˜์ง€ ์•Š์Œ์„ ๋ณด์žฅํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

let a: number[] = [1, 2, 3, 4];
let ro: ReadonlyArray<number> = a;
ro[0] = 12; // ์˜ค๋ฅ˜!
ro.push(5); // ์˜ค๋ฅ˜!
ro.length = 100; // ์˜ค๋ฅ˜!
a = ro; // ์˜ค๋ฅ˜!

์˜ˆ์ œ ๋งˆ์ง€๋ง‰ ์ค„์—์„œ ReadonlyArray๋ฅผ ์ผ๋ฐ˜ ๋ฐฐ์—ด์— ์žฌํ• ๋‹น์ด ๋ถˆ๊ฐ€๋Šฅํ•œ ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํƒ€์ž… ๋‹จ์–ธ(type assertion)์œผ๋กœ ์˜ค๋ฒ„๋ผ์ด๋“œํ•˜๋Š” ๊ฒƒ์€ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค:

a = ro as number[];

readonly vs const

readonly์™€ const ์ค‘์— ์–ด๋–ค ๊ฒƒ์„ ์‚ฌ์šฉํ•  ์ง€ ๊ธฐ์–ตํ•˜๊ธฐ ๊ฐ€์žฅ ์‰ฌ์šด ๋ฐฉ๋ฒ•์€ ๋ณ€์ˆ˜์™€ ํ”„๋กœํผํ‹ฐ์ค‘ ์–ด๋””์— ์‚ฌ์šฉํ• ์ง€ ์งˆ๋ฌธํ•ด ๋ณด๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋ณ€์ˆ˜๋Š” const๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ํ”„๋กœํผํ‹ฐ๋Š” readonly๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค

์ดˆ๊ณผ ํ”„๋กœํผํ‹ฐ ๊ฒ€์‚ฌ (Excess Property Checks)

์ธํ„ฐํŽ˜์ด์Šค์˜ ์ฒซ ๋ฒˆ์งธ ์˜ˆ์ œ์—์„œ TypeScript๊ฐ€ { label: string; }์„ ๊ธฐ๋Œ€ํ•ด๋„ { size: number; label: string; }๋ฅผ ํ—ˆ์šฉํ•ด์ฃผ์—ˆ์Šต๋‹ˆ๋‹ค. ๋˜ํ•œ ์„ ํƒ์  ํ”„๋กœํผํ‹ฐ๋ฅผ ๋ฐฐ์šฐ๊ณ , ์†Œ์œ„ "option bags"์„ ๊ธฐ์ˆ ํ•  ๋•Œ, ์œ ์šฉํ•˜๋‹ค๋Š” ๊ฒƒ์„ ๋ฐฐ์› ์Šต๋‹ˆ๋‹ค.

ํ•˜์ง€๋งŒ, ๊ทธ๋ƒฅ ๊ทธ ๋‘˜์„ ๊ฒฐํ•ฉํ•˜๋ฉด ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, createSquare๋ฅผ ์‚ฌ์šฉํ•œ ๋งˆ์ง€๋ง‰ ์˜ˆ์ œ๋ฅผ ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค:

interface SquareConfig {
    color?: string;
    width?: number;
}

function createSquare(config: SquareConfig): { color: string; area: number } {
    // ...
}

let mySquare = createSquare({ colour: "red", width: 100 });

createSquare์˜ ๋งค๊ฐœ๋ณ€์ˆ˜๊ฐ€ color๋Œ€์‹  colour๋กœ ์ „๋‹ฌ๋œ ๊ฒƒ์— ์œ ์˜ํ•˜์„ธ์š”. ์ด ๊ฒฝ์šฐ JavaScript์—์„  ์กฐ์šฉํžˆ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.

width ํ”„๋กœํผํ‹ฐ๋Š” ์ ํ•ฉํ•˜๊ณ , color ํ”„๋กœํผํ‹ฐ๋Š” ์—†๊ณ , ์ถ”๊ฐ€ colour ํ”„๋กœํผํ‹ฐ๋Š” ์ค‘์š”ํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์—, ์ด ํ”„๋กœ๊ทธ๋žจ์ด ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์ž‘์„ฑ๋˜์—ˆ๋‹ค๊ณ  ์ƒ๊ฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

ํ•˜์ง€๋งŒ, TypeScript๋Š” ์ด ์ฝ”๋“œ์— ๋ฒ„๊ทธ๊ฐ€ ์žˆ์„ ์ˆ˜ ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ๊ฐ์ฒด ๋ฆฌํ„ฐ๋Ÿด์€ ๋‹ค๋ฅธ ๋ณ€์ˆ˜์— ํ• ๋‹นํ•  ๋•Œ๋‚˜ ์ธ์ˆ˜๋กœ ์ „๋‹ฌํ•  ๋•Œ, ํŠน๋ณ„ํ•œ ์ฒ˜๋ฆฌ๋ฅผ ๋ฐ›๊ณ , *์ดˆ๊ณผ ํ”„๋กœํผํ‹ฐ ๊ฒ€์‚ฌ (excess property checking)*๋ฅผ ๋ฐ›์Šต๋‹ˆ๋‹ค. ๋งŒ์•ฝ ๊ฐ์ฒด ๋ฆฌํ„ฐ๋Ÿด์ด "๋Œ€์ƒ ํƒ€์ž… (target type)"์ด ๊ฐ–๊ณ  ์žˆ์ง€ ์•Š์€ ํ”„๋กœํผํ‹ฐ๋ฅผ ๊ฐ–๊ณ  ์žˆ์œผ๋ฉด, ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.

// error: Object literal may only specify known properties, but 'colour' does not exist in type 'SquareConfig'. Did you mean to write 'color'?
let mySquare = createSquare({ colour: "red", width: 100 });

์ด ๊ฒ€์‚ฌ๋ฅผ ํ”ผํ•˜๋Š” ๋ฐฉ๋ฒ•์€ ์ •๋ง ๊ฐ„๋‹จํ•ฉ๋‹ˆ๋‹ค. ๊ฐ€์žฅ ๊ฐ„๋‹จํ•œ ๋ฐฉ๋ฒ•์€ ํƒ€์ž… ๋‹จ์–ธ์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค:

let mySquare = createSquare({ width: 100, opacity: 0.5 } as SquareConfig);

ํ•˜์ง€๋งŒ ํŠน๋ณ„ํ•œ ๊ฒฝ์šฐ์—, ์ถ”๊ฐ€ ํ”„๋กœํผํ‹ฐ๊ฐ€ ์žˆ์Œ์„ ํ™•์‹ ํ•œ๋‹ค๋ฉด, ๋ฌธ์ž์—ด ์ธ๋ฑ์Šค ์„œ๋ช…(string index signatuer)์„ ์ถ”๊ฐ€ํ•˜๋Š” ๊ฒƒ์ด ๋” ๋‚˜์€ ๋ฐฉ๋ฒ•์ž…๋‹ˆ๋‹ค. ๋งŒ์•ฝ SquareConfig color์™€ width ํ”„๋กœํผํ‹ฐ๋ฅผ ์œ„์™€ ๊ฐ™์€ ํƒ€์ž…์œผ๋กœ ๊ฐ–๊ณ  ์žˆ๊ณ , ๋˜ํ•œ ๋‹ค๋ฅธ ํ”„๋กœํผํ‹ฐ๋ฅผ ๊ฐ€์งˆ ์ˆ˜ ์žˆ๋‹ค๋ฉด, ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ •์˜ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

interface SquareConfig {
    color?: string;
    width?: number;
    [propName: string]: any;
}

๋‚˜์ค‘์— ์ธ๋ฑ์Šค ์„œ๋ช…์— ๋Œ€ํ•ด ์ข€ ๋” ๋‹ค๋ฃฐ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ์—ฌ๊ธฐ์„œ๋Š” SquareConfig๊ฐ€ ์—ฌ๋Ÿฌ ํ”„๋กœํผํ‹ฐ๋ฅผ ๊ฐ€์งˆ ์ˆ˜ ์žˆ๊ณ , ๊ทธ ํ”„๋กœํผํ‹ฐ๋“ค์ด color๋‚˜ width๊ฐ€ ์•„๋‹ˆ๋ผ๋ฉด, ๊ทธ๋“ค์˜ ํƒ€์ž…์€ ์ค‘์š”ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์ด ๊ฒ€์‚ฌ๋ฅผ ํ”ผํ•˜๋Š” ๋งˆ์ง€๋ง‰ ๋ฐฉ๋ฒ•์€ ๋†€๋ž๊ฒŒ๋„ ๊ฐ์ฒด๋ฅผ ๋‹ค๋ฅธ ๋ณ€์ˆ˜์— ํ• ๋‹นํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. squareOptions๊ฐ€ ์ถ”๊ฐ€ ํ”„๋กœํผํ‹ฐ ๊ฒ€์‚ฌ๋ฅผ ๋ฐ›์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์—, ์ปดํŒŒ์ผ๋Ÿฌ๋Š” ์—๋Ÿฌ๋ฅผ ์ฃผ์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

let squareOptions = { colour: "red", width: 100 };
let mySquare = createSquare(squareOptions);

squareOptions์™€ SquareConfig ์‚ฌ์ด์— ๊ณตํ†ต ํ”„๋กœํผํ‹ฐ๊ฐ€ ์žˆ๋Š” ๊ฒฝ์šฐ์—๋งŒ ์œ„์™€ ๊ฐ™์€ ๋ฐฉ๋ฒ•์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ์˜ˆ์ œ์—์„œ๋Š”, width๊ฐ€ ๊ทธ ๊ฒฝ์šฐ์ž…๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ๋งŒ์•ฝ์— ๋ณ€์ˆ˜๊ฐ€ ๊ณตํ†ต ๊ฐ์ฒด ํ”„๋กœํผํ‹ฐ๊ฐ€ ์—†์œผ๋ฉด ์—๋Ÿฌ๊ฐ€ ๋‚ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด:

let squareOptions = { colour: "red" };
let mySquare = createSquare(squareOptions);

์œ„์ฒ˜๋Ÿผ ๊ฐ„๋‹จํ•œ ์ฝ”๋“œ์˜ ๊ฒฝ์šฐ, ์ด ๊ฒ€์‚ฌ๋ฅผ "ํ”ผํ•˜๋Š”" ๋ฐฉ๋ฒ•์„ ์‹œ๋„ํ•˜์ง€ ์•Š๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค. ๋ฉ”์„œ๋“œ๊ฐ€ ์žˆ๊ณ  ์ƒํƒœ๋ฅผ ๊ฐ€์ง€๋Š” ๋“ฑ ๋” ๋ณต์žกํ•œ ๊ฐ์ฒด ๋ฆฌํ„ฐ๋Ÿด์—์„œ ์ด ๋ฐฉ๋ฒ•์„ ์ƒ๊ฐํ•ด๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ์ดˆ๊ณผ ํ”„๋กœํผํ‹ฐ ์—๋Ÿฌ์˜ ๋Œ€๋ถ€๋ถ„์€ ์‹ค์ œ ๋ฒ„๊ทธ์ž…๋‹ˆ๋‹ค. ๊ทธ ๋ง์€, ๋งŒ์•ฝ ์˜ต์…˜ ๋ฐฑ ๊ฐ™์€ ๊ณณ์—์„œ ์ดˆ๊ณผ ํ”„๋กœํผํ‹ฐ ๊ฒ€์‚ฌ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•˜๋ฉด, ํƒ€์ž… ์ •์˜๋ฅผ ์ˆ˜์ •ํ•ด์•ผ ํ•  ํ•„์š”๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, ๋งŒ์•ฝ createSquare์— color๋‚˜ colour ๋ชจ๋‘ ์ „๋‹ฌํ•ด๋„ ๊ดœ์ฐฎ๋‹ค๋ฉด, squareConfig๊ฐ€ ์ด๋ฅผ ๋ฐ˜์˜ํ•˜๋„๋ก ์ •์˜๋ฅผ ์ˆ˜์ •ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

ํ•จ์ˆ˜ ํƒ€์ž… (Function Types)

์ธํ„ฐํŽ˜์ด์Šค๋Š” JavaScript ๊ฐ์ฒด๊ฐ€ ๊ฐ€์งˆ ์ˆ˜ ์žˆ๋Š” ๋„“์€ ๋ฒ”์œ„์˜ ํ˜•ํƒœ๋ฅผ ๊ธฐ์ˆ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํ”„๋กœํผํ‹ฐ๋กœ ๊ฐ์ฒด๋ฅผ ๊ธฐ์ˆ ํ•˜๋Š” ๊ฒƒ ์™ธ์—, ์ธํ„ฐํŽ˜์ด์Šค๋Š” ํ•จ์ˆ˜ ํƒ€์ž…์„ ์„ค๋ช…ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ธํ„ฐํŽ˜์ด์Šค๋กœ ํ•จ์ˆ˜ ํƒ€์ž…์„ ๊ธฐ์ˆ ํ•˜๊ธฐ ์œ„ํ•ด, ์ธํ„ฐํŽ˜์ด์Šค์— ํ˜ธ์ถœ ์„œ๋ช… (call signature)๋ฅผ ์ „๋‹ฌํ•ฉ๋‹ˆ๋‹ค. ์ด๋Š” ๋งค๊ฐœ๋ณ€์ˆ˜ ๋ชฉ๋ก๊ณผ ๋ฐ˜ํ™˜ ํƒ€์ž…๋งŒ ์ฃผ์–ด์ง„ ํ•จ์ˆ˜ ์„ ์–ธ๊ณผ ๋น„์Šทํ•ฉ๋‹ˆ๋‹ค. ๊ฐ ๋งค๊ฐœ๋ณ€์ˆ˜๋Š” ์ด๋ฆ„๊ณผ ํƒ€์ž…์ด ๋ชจ๋‘ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.

interface SearchFunc {
    (source: string, subString: string): boolean;
}

ํ•œ๋ฒˆ ์ •์˜๋˜๋ฉด, ํ•จ์ˆ˜ ํƒ€์ž… ์ธํ„ฐํŽ˜์ด์Šค๋Š” ๋‹ค๋ฅธ ์ธํ„ฐํŽ˜์ด์Šค์ฒ˜๋Ÿผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์„œ ํ•จ์ˆ˜ ํƒ€์ž…์˜ ๋ณ€์ˆ˜๋ฅผ ๋งŒ๋“ค๊ณ , ๊ฐ™์€ ํƒ€์ž…์˜ ํ•จ์ˆ˜ ๊ฐ’์œผ๋กœ ํ• ๋‹นํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ๋ณด์—ฌ์ค๋‹ˆ๋‹ค.

let mySearch: SearchFunc;
mySearch = function(source: string, subString: string) {
    let result = source.search(subString);
    return result > -1;
}

์˜ฌ๋ฐ”๋ฅธ ํ•จ์ˆ˜ ํƒ€์ž… ๊ฒ€์‚ฌ๋ฅผ ์œ„ํ•ด, ๋งค๊ฐœ๋ณ€์ˆ˜์˜ ์ด๋ฆ„์ด ๊ฐ™์„ ํ•„์š”๋Š” ์—†์Šต๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, ์œ„์˜ ์˜ˆ์ œ๋ฅผ ์•„๋ž˜์™€ ๊ฐ™์ด ์“ธ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

let mySearch: SearchFunc;
mySearch = function(src: string, sub: string): boolean {
    let result = src.search(sub);
    return result > -1;
}

ํ•จ์ˆ˜ ๋งค๊ฐœ๋ณ€์ˆ˜๋“ค์€ ๊ฐ™์€ ์œ„์น˜์— ๋Œ€์‘๋˜๋Š” ๋งค๊ฐœ๋ณ€์ˆ˜๋ผ๋ฆฌ ํ•œ๋ฒˆ์— ํ•˜๋‚˜์”ฉ ๊ฒ€์‚ฌํ•ฉ๋‹ˆ๋‹ค. ๋งŒ์•ฝ ํƒ€์ž…์„ ์ „ํ˜€ ์ง€์ •ํ•˜์ง€ ์•Š๊ณ  ์‹ถ๋‹ค๋ฉด, SearchFunc ํƒ€์ž…์˜ ๋ณ€์ˆ˜๋กœ ์ง์ ‘ ํ•จ์ˆ˜ ๊ฐ’์ด ํ• ๋‹น๋˜์—ˆ๊ธฐ ๋•Œ๋ฌธ์— TypeScript์˜ ๋ฌธ๋งฅ์ƒ ํƒ€์ดํ•‘ (contextual typing)์ด ์ธ์ˆ˜ ํƒ€์ž…์„ ์ถ”๋ก ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ์˜ˆ์ œ์—์„œ, ํ•จ์ˆ˜ ํ‘œํ˜„์˜ ๋ฐ˜ํ™˜ ํƒ€์ž…์ด ๋ฐ˜ํ™˜ํ•˜๋Š” ๊ฐ’์œผ๋กœ ์ถ”๋ก ๋ฉ๋‹ˆ๋‹ค. (์—ฌ๊ธฐ์„œ๋Š” false์™€ true)

let mySearch: SearchFunc;
mySearch = function(src, sub) {
    let result = src.search(sub);
    return result > -1;
}

ํ•จ์ˆ˜ ํ‘œํ˜„์‹์ด ์ˆซ์ž ๋‚˜ ๋ฌธ์ž์—ด์„ ๋ฐ˜ํ™˜ํ–ˆ๋‹ค๋ฉด, ํƒ€์ž… ๊ฒ€์‚ฌ๋Š” ๋ฐ˜ํ™˜ ํƒ€์ž…์ด SearchFunc ์ธํ„ฐํŽ˜์ด์Šค์— ์ •์˜๋œ ๋ฐ˜ํ™˜ ํƒ€์ž…๊ณผ ์ผ์น˜ํ•˜์ง€ ์•Š๋Š”๋‹ค๋Š” ์—๋Ÿฌ๋ฅผ ๋ฐœ์ƒ์‹œํ‚ต๋‹ˆ๋‹ค.

let mySearch: SearchFunc;

// error: Type '(src: string, sub: string) => string' is not assignable to type 'SearchFunc'.
// Type 'string' is not assignable to type 'boolean'.
mySearch = function(src, sub) {
  let result = src.search(sub);
  return "string";
};

์ธ๋ฑ์„œ๋ธ” ํƒ€์ž… (Indexable Types)

์ธํ„ฐํŽ˜์ด์Šค๋กœ ํ•จ์ˆ˜ ํƒ€์ž…์„ ์„ค๋ช…ํ•˜๋Š” ๋ฐฉ๋ฒ•๊ณผ ์œ ์‚ฌํ•˜๊ฒŒ, a[10] ์ด๋‚˜ ageMap["daniel"] ์ฒ˜๋Ÿผ ํƒ€์ž…์„ "์ธ๋ฑ์Šค๋กœ" ๊ธฐ์ˆ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ธ๋ฑ์„œ๋ธ” ํƒ€์ž…์€ ์ธ๋ฑ์‹ฑ ํ• ๋•Œ ํ•ด๋‹น ๋ฐ˜ํ™˜ ์œ ํ˜•๊ณผ ํ•จ๊ป˜ ๊ฐ์ฒด๋ฅผ ์ธ๋ฑ์‹ฑํ•˜๋Š” ๋ฐ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ํƒ€์ž…์„ ๊ธฐ์ˆ ํ•˜๋Š” *์ธ๋ฑ์Šค ์‹œ๊ทธ๋‹ˆ์ฒ˜ (index signature)*๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ์˜ˆ์ œ๋ฅผ ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค:

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

let myArray: StringArray;
myArray = ["Bob", "Fred"];

let myStr: string = myArray[0];

์œ„์—์„œ ์ธ๋ฑ์Šค ์„œ๋ช…์ด ์žˆ๋Š” StringArray ์ธํ„ฐํŽ˜์ด์Šค๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ์ธ๋ฑ์Šค ์„œ๋ช…์€ StringArray๊ฐ€ number๋กœ ์ƒ‰์ธํ™”(indexed)๋˜๋ฉด string์„ ๋ฐ˜ํ™˜ํ•  ๊ฒƒ์„ ๋‚˜ํƒ€๋ƒ…๋‹ˆ๋‹ค.

์ธ๋ฑ์Šค ์„œ๋ช…์„ ์ง€์›ํ•˜๋Š” ํƒ€์ž…์—๋Š” ๋‘ ๊ฐ€์ง€๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค: ๋ฌธ์ž์—ด๊ณผ ์ˆซ์ž.

๋‘ ํƒ€์ž…์˜ ์ธ๋ฑ์„œ(indexer)๋ฅผ ๋ชจ๋‘ ์ง€์›ํ•˜๋Š” ๊ฒƒ์€ ๊ฐ€๋Šฅํ•˜์ง€๋งŒ, ์ˆซ์ž ์ธ๋ฑ์„œ์—์„œ ๋ฐ˜ํ™˜๋œ ํƒ€์ž…์€ ๋ฐ˜๋“œ์‹œ ๋ฌธ์ž์—ด ์ธ๋ฑ์„œ์—์„œ ๋ฐ˜ํ™˜๋œ ํƒ€์ž…์˜ ํ•˜์œ„ ํƒ€์ž…(subtype)์ด์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ด ์ด์œ ๋Š” number๋กœ ์ธ๋ฑ์‹ฑ ํ•  ๋•Œ, JavaScript๋Š” ์‹ค์ œ๋กœ ๊ฐ์ฒด๋ฅผ ์ธ๋ฑ์‹ฑํ•˜๊ธฐ ์ „์— string์œผ๋กœ ๋ณ€ํ™˜ํ•˜๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ์ฆ‰, 100 (number)๋กœ ์ธ๋ฑ์‹ฑํ•˜๋Š” ๊ฒƒ์€ "100" (string)๋กœ ์ธ๋ฑ์‹ฑํ•˜๋Š” ๊ฒƒ๊ณผ ๊ฐ™๊ธฐ ๋•Œ๋ฌธ์—, ์„œ๋กœ ์ผ๊ด€์„ฑ ์žˆ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

class Animal {
    name: string;
}
class Dog extends Animal {
    breed: string;
}

// ์˜ค๋ฅ˜: ์ˆซ์žํ˜• ๋ฌธ์ž์—ด๋กœ ์ธ๋ฑ์‹ฑ์„ ํ•˜๋ฉด ์™„์ „ํžˆ ๋‹ค๋ฅธ ํƒ€์ž…์˜ Animal์„ ์–ป๊ฒŒ ๋  ๊ฒƒ์ž…๋‹ˆ๋‹ค!
interface NotOkay {
    [x: number]: Animal;
    [x: string]: Dog;
}

๋ฌธ์ž์—ด ์ธ๋ฑ์Šค ์‹œ๊ทธ๋‹ˆ์ฒ˜๋Š” "์‚ฌ์ „" ํŒจํ„ด์„ ๊ธฐ์ˆ ํ•˜๋Š”๋ฐ ๊ฐ•๋ ฅํ•œ ๋ฐฉ๋ฒ•์ด์ง€๋งŒ, ๋ชจ๋“  ํ”„๋กœํผํ‹ฐ๋“ค์ด ๋ฐ˜ํ™˜ ํƒ€์ž…๊ณผ ์ผ์น˜ํ•˜๋„๋ก ๊ฐ•์ œํ•ฉ๋‹ˆ๋‹ค. ๋ฌธ์ž์—ด ์ธ๋ฑ์Šค๊ฐ€ obj.property๊ฐ€ obj["property"]๋กœ๋„ ์ด์šฉ ๊ฐ€๋Šฅํ•จ์„ ์•Œ๋ ค์ฃผ๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ๋‹ค์Œ ์˜ˆ์ œ์—์„œ, name์˜ ํƒ€์ž…์€ ๋ฌธ์ž์—ด ์ธ๋ฑ์Šค ํƒ€์ž…๊ณผ ์ผ์น˜ํ•˜์ง€ ์•Š๊ณ , ํƒ€์ž… ๊ฒ€์‚ฌ๋Š” ์—๋Ÿฌ๋ฅผ ๋ฐœ์ƒ์‹œํ‚ต๋‹ˆ๋‹ค.

interface NumberDictionary {
    [index: string]: number;
    length: number;    // ์„ฑ๊ณต, length๋Š” ์ˆซ์ž์ž…๋‹ˆ๋‹ค
    name: string;      // ์˜ค๋ฅ˜, `name`์˜ ํƒ€์ž…์€ ์ธ๋ฑ์„œ์˜ ํ•˜์œ„ํƒ€์ž…์ด ์•„๋‹™๋‹ˆ๋‹ค
}

ํ•˜์ง€๋งŒ, ์ธ๋ฑ์Šค ์‹œ๊ทธ๋‹ˆ์ฒ˜๊ฐ€ ํ”„๋กœํผํ‹ฐ ํƒ€์ž…๋“ค์˜ ํ•ฉ์ง‘ํ•ฉ์ด๋ผ๋ฉด ๋‹ค๋ฅธ ํƒ€์ž…์˜ ํ”„๋กœํผํ‹ฐ๋“ค๋„ ํ—ˆ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

interface NumberOrStringDictionary {
    [index: string]: number | string;
    length: number;    // ์„ฑ๊ณต, length๋Š” ์ˆซ์ž์ž…๋‹ˆ๋‹ค
    name: string;      // ์„ฑ๊ณต, name์€ ๋ฌธ์ž์—ด์ž…๋‹ˆ๋‹ค
}

๋งˆ์ง€๋ง‰์œผ๋กœ, ์ธ๋ฑ์Šค์˜ ํ• ๋‹น์„ ๋ง‰๊ธฐ ์œ„ํ•ด ์ธ๋ฑ์Šค ์‹œ๊ทธ๋‹ˆ์ฒ˜๋ฅผ ์ฝ๊ธฐ ์ „์šฉ์œผ๋กœ ๋งŒ๋“ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

interface ReadonlyStringArray {
    readonly [index: number]: string;
}
let myArray: ReadonlyStringArray = ["Alice", "Bob"];
myArray[2] = "Mallory"; // ์˜ค๋ฅ˜!

์ธ๋ฑ์Šค ์‹œ๊ทธ๋‹ˆ์ฒ˜๊ฐ€ ์ฝ๊ธฐ ์ „์šฉ์ด๊ธฐ ๋•Œ๋ฌธ์— myArray[2]์˜ ๊ฐ’์„ ํ• ๋‹นํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

ํด๋ž˜์Šค ํƒ€์ž… (Class Types)

์ธํ„ฐํŽ˜์ด์Šค ๊ตฌํ˜„ํ•˜๊ธฐ (Implementing an interface)

ํด๋ž˜์Šค๊ฐ€ ํŠน์ • ๊ณ„์•ฝ(contract)์„ ์ถฉ์กฑ์‹œํ‚ค๋„๋ก ๋ช…์‹œ์ ์œผ๋กœ ๊ฐ•์ œํ•˜๋Š” C#๊ณผ Java์™€ ๊ฐ™์€ ์–ธ์–ด์—์„œ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฐ€์žฅ ์ผ๋ฐ˜์ ์ธ ๋ฐฉ๋ฒ•์€ TypeScript์—์„œ๋„ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.

interface ClockInterface {
    currentTime: Date;
}

class Clock implements ClockInterface {
    currentTime: Date = new Date();
    constructor(h: number, m: number) { }
}

์•„๋ž˜ ์˜ˆ์ œ์˜ setTime ์ฒ˜๋Ÿผ ํด๋ž˜์Šค์— ๊ตฌํ˜„๋œ ๋ฉ”์„œ๋“œ๋ฅผ ์ธํ„ฐํŽ˜์ด์Šค ์•ˆ์—์„œ๋„ ๊ธฐ์ˆ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

interface ClockInterface {
    currentTime: Date;
    setTime(d: Date): void;
}

class Clock implements ClockInterface {
    currentTime: Date = new Date();
    setTime(d: Date) {
        this.currentTime = d;
    }
    constructor(h: number, m: number) { }
}

์ธํ„ฐํŽ˜์ด์Šค๋Š” ํด๋ž˜์Šค์˜ public๊ณผ private ๋ชจ๋‘๋ณด๋‹ค๋Š”, public์„ ๊ธฐ์ˆ ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ ํด๋ž˜์Šค ์ธ์Šคํ„ด์Šค์˜ private์—์„œ๋Š” ํŠน์ • ํƒ€์ž…์ด ์žˆ๋Š”์ง€ ๊ฒ€์‚ฌํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

ํด๋ž˜์Šค์˜ ์Šคํƒœํ‹ฑ๊ณผ ์ธ์Šคํ„ด์Šค์˜ ์ฐจ์ด์  (Difference between the static and instance sides of classes)

ํด๋ž˜์Šค์™€ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๋‹ค๋ฃฐ ๋•Œ, ํด๋ž˜์Šค๋Š” ๋‘ ๊ฐ€์ง€ ํƒ€์ž…์„ ๊ฐ€์ง„๋‹ค๋Š” ๊ฒƒ์„ ๊ธฐ์–ตํ•˜๋Š” ๊ฒŒ ์ข‹์Šต๋‹ˆ๋‹ค: ์Šคํƒœํ‹ฑ ํƒ€์ž…๊ณผ ์ธ์Šคํ„ด์Šค ํƒ€์ž…์ž…๋‹ˆ๋‹ค. ์ƒ์„ฑ ์‹œ๊ทธ๋‹ˆ์ฒ˜ (construct signature)๋กœ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์ƒ์„ฑํ•˜๊ณ , ํด๋ž˜์Šค๋ฅผ ์ƒ์„ฑํ•˜๋ ค๊ณ  ํ•œ๋‹ค๋ฉด, ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ implements ํ•  ๋•Œ, ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•˜๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์„ ๊ฒ๋‹ˆ๋‹ค:

interface ClockConstructor {
    new (hour: number, minute: number);
}

class Clock implements ClockConstructor {
    currentTime: Date;
    constructor(h: number, m: number) { }
}

ํด๋ž˜์Šค๊ฐ€ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ implements ํ•  ๋•Œ, ํด๋ž˜์Šค์˜ ์ธ์Šคํ„ด์Šค๋งŒ ๊ฒ€์‚ฌํ•˜๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ์ƒ์„ฑ์ž๊ฐ€ ์Šคํƒœํ‹ฑ์ด๊ธฐ ๋•Œ๋ฌธ์—, ์ด ๊ฒ€์‚ฌ์— ํฌํ•จ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

๋Œ€์‹ ์—, ํด๋ž˜์Šค์˜ ์Šคํƒœํ‹ฑ ๋ถ€๋ถ„์„ ์ง์ ‘์ ์œผ๋กœ ๋‹ค๋ฃฐ ํ•„์š”๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋ฒˆ ์˜ˆ์ œ์—์„œ, ClockConstructor๋Š” ์ƒ์„ฑ์ž๋ฅผ ์ •์˜ํ•˜๊ณ , ClockInterface๋Š” ์ธ์Šคํ„ด์Šค ๋ฉ”์„œ๋“œ๋ฅผ ์ •์˜ํ•˜๋Š” ๋‘ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์ •์˜ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ , ํŽธ์˜๋ฅผ ์œ„ํ•ด, ์ „๋‹ฌ๋œ ํƒ€์ž…์˜ ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•˜๋Š” createClock ์ƒ์„ฑ์ž ํ•จ์ˆ˜๋ฅผ ์ •์˜ํ•ฉ๋‹ˆ๋‹ค:

interface ClockConstructor {
    new (hour: number, minute: number): ClockInterface;
}
interface ClockInterface {
    tick(): void;
}

function createClock(ctor: ClockConstructor, hour: number, minute: number): ClockInterface {
    return new ctor(hour, minute);
}

class DigitalClock implements ClockInterface {
    constructor(h: number, m: number) { }
    tick() {
        console.log("beep beep");
    }
}
class AnalogClock implements ClockInterface {
    constructor(h: number, m: number) { }
    tick() {
        console.log("tick tock");
    }
}

let digital = createClock(DigitalClock, 12, 17);
let analog = createClock(AnalogClock, 7, 32);

createClock์˜ ์ฒซ ๋ฒˆ์งธ ๋งค๊ฐœ๋ณ€์ˆ˜๋Š” createClock(AnalogClock, 7, 32)์•ˆ์— ClockConstructor ํƒ€์ž…์ด๋ฏ€๋กœ, AnalogClock์ด ์˜ฌ๋ฐ”๋ฅธ ์ƒ์„ฑ์ž ์‹œ๊ทธ๋‹ˆ์ฒ˜๋ฅผ ๊ฐ–๊ณ  ์žˆ๋Š”์ง€ ๊ฒ€์‚ฌํ•ฉ๋‹ˆ๋‹ค.

๋˜ ๋‹ค๋ฅธ ์‰ฌ์šด ๋ฐฉ๋ฒ•์€ ํด๋ž˜์Šค ํ‘œํ˜„์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

interface ClockConstructor {
  new (hour: number, minute: number);
}

interface ClockInterface {
  tick();
}

const Clock: ClockConstructor = class Clock implements ClockInterface {
  constructor(h: number, m: number) {}
  tick() {
      console.log("beep beep");
  }
}

์ธํ„ฐํŽ˜์ด์Šค ํ™•์žฅํ•˜๊ธฐ (Extending Interfaces)

ํด๋ž˜์Šค์ฒ˜๋Ÿผ, ์ธํ„ฐํŽ˜์ด์Šค๋“ค๋„ ํ™•์žฅ(extend)์ด ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค. ์ด๋Š” ํ•œ ์ธํ„ฐํŽ˜์ด์Šค์˜ ๋ฉค๋ฒ„๋ฅผ ๋‹ค๋ฅธ ์ธํ„ฐํŽ˜์ด์Šค์— ๋ณต์‚ฌํ•˜๋Š” ๊ฒƒ์„ ๊ฐ€๋Šฅํ•˜๊ฒŒ ํ•ด์ฃผ๋Š”๋ฐ, ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์žฌ์‚ฌ์šฉ์„ฑ ๋†’์€ ์ปดํฌ๋„ŒํŠธ๋กœ ์ชผ๊ฐค ๋•Œ, ์œ ์—ฐํ•จ์„ ์ œ๊ณตํ•ด์ค๋‹ˆ๋‹ค.

interface Shape {
    color: string;
}

interface Square extends Shape {
    sideLength: number;
}

let square = {} as Square;
square.color = "blue";
square.sideLength = 10;

์ธํ„ฐํŽ˜์ด์Šค๋Š” ์—ฌ๋Ÿฌ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ํ™•์žฅํ•  ์ˆ˜ ์žˆ์–ด, ๋ชจ๋“  ์ธํ„ฐํŽ˜์ด์Šค์˜ ์กฐํ•ฉ์„ ๋งŒ๋“ค์–ด๋‚ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

interface Shape {
    color: string;
}

interface PenStroke {
    penWidth: number;
}

interface Square extends Shape, PenStroke {
    sideLength: number;
}

let square = {} as Square;
square.color = "blue";
square.sideLength = 10;
square.penWidth = 5.0;

ํ•˜์ด๋ธŒ๋ฆฌ๋“œ ํƒ€์ž… (Hybrid Types)

์ผ์ฐ์ด ์–ธ๊ธ‰ํ–ˆ๋“ฏ์ด, ์ธํ„ฐํŽ˜์ด์Šค๋Š” ์‹ค์ œ JavaScript ์„ธ๊ณ„์— ์กด์žฌํ•˜๋Š” ๋‹ค์–‘ํ•œ ํƒ€์ž…๋“ค์„ ๊ธฐ์ˆ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. JavaScript์˜ ๋™์ ์ด๊ณ  ์œ ์—ฐํ•œ ํŠน์„ฑ ๋•Œ๋ฌธ์—, ์œ„์—์„œ ์„ค๋ช…ํ–ˆ๋˜ ๋ช‡๋ช‡ ํƒ€์ž…์˜ ์กฐํ•ฉ์œผ๋กœ ๋™์ž‘ํ•˜๋Š” ๊ฐ์ฒด๋ฅผ ๊ฐ€๋” ๋งˆ์ฃผํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ทธ๋Ÿฌํ•œ ์˜ˆ์ œ ์ค‘ ํ•˜๋‚˜๋Š” ์ถ”๊ฐ€์ ์ธ ํ”„๋กœํผํ‹ฐ์™€ ํ•จ๊ป˜, ํ•จ์ˆ˜์™€ ๊ฐ์ฒด ์—ญํ•  ๋ชจ๋‘ ์ˆ˜ํ–‰ํ•˜๋Š” ๊ฐ์ฒด์ž…๋‹ˆ๋‹ค:

interface Counter {
    (start: number): string;
    interval: number;
    reset(): void;
}

function getCounter(): Counter {
    let counter = (function (start: number) { }) as Counter;
    counter.interval = 123;
    counter.reset = function () { };
    return counter;
}

let c = getCounter();
c(10);
c.reset();
c.interval = 5.0;

์จ๋“œํŒŒํ‹ฐ (3rd-party) JavaScript์™€ ์ƒํ˜ธ์ž‘์šฉํ•  ๋•Œ, ํƒ€์ž…์˜ ํ˜•ํƒœ๋ฅผ ์™„์ „ํžˆ ๊ธฐ์ˆ ํ•˜๊ธฐ ์œ„ํ•ด ์œ„์™€ ๊ฐ™์€ ํŒจํ„ด์„ ์‚ฌ์šฉํ•ด์•ผํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

ํด๋ž˜์Šค๋ฅผ ํ™•์žฅํ•œ ์ธํ„ฐํŽ˜์ด์Šค (Interfaces Extending Classes)

์ธํ„ฐํŽ˜์ด์Šค ํƒ€์ž…์ด ํด๋ž˜์Šค ํƒ€์ž…์„ ํ™•์žฅํ•˜๋ฉด, ํด๋ž˜์Šค์˜ ๋ฉค๋ฒ„๋Š” ์ƒ์†๋ฐ›์ง€๋งŒ ๊ตฌํ˜„์€ ์ƒ์†๋ฐ›์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ ์ธํ„ฐํŽ˜์ด์Šค๊ฐ€ ๊ตฌํ˜„์„ ์ œ๊ณตํ•˜์ง€ ์•Š๊ณ , ํด๋ž˜์Šค์˜ ๋ฉค๋ฒ„ ๋ชจ๋‘๋ฅผ ์„ ์–ธํ•œ ๊ฒƒ๊ณผ ๋งˆ์ฐฌ๊ฐ€์ง€์ž…๋‹ˆ๋‹ค. ์ธํ„ฐํŽ˜์ด์Šค๋Š” ์‹ฌ์ง€์–ด ๊ธฐ์ดˆ ํด๋ž˜์Šค์˜ private๊ณผ protected ๋ฉค๋ฒ„๋„ ์ƒ์†๋ฐ›์Šต๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ ์ธํ„ฐํŽ˜์ด์Šค๊ฐ€ private ํ˜น์€ protected ๋ฉค๋ฒ„๋ฅผ ํฌํ•จํ•œ ํด๋ž˜์Šค๋ฅผ ํ™•์žฅํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ๋œป์ด๊ณ , ์ธํ„ฐํŽ˜์ด์Šค ํƒ€์ž…์€ ๊ทธ ํด๋ž˜์Šค๋‚˜ ํ•˜์œ„ํด๋ž˜์Šค์— ์˜ํ•ด์„œ๋งŒ ๊ตฌํ˜„๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ด๋Š” ๊ฑฐ๋Œ€ํ•œ ์ƒ์†๊ณ„์ธต์„ ๊ฐ€์ง€๊ณ  ์žˆ์„ ๋•Œ ์œ ์šฉํ•˜์ง€๋งŒ, ํŠน์ • ํ”„๋กœํผํ‹ฐ๋ฅผ ๊ฐ€์ง„ ํ•˜์œ„ํด๋ž˜์Šค์—์„œ๋งŒ ์ฝ”๋“œ๊ฐ€ ๋™์ž‘ํ•˜๋„๋ก ์ง€์ •ํ•˜๋Š”๋ฐ๋„ ์œ ์šฉํ•ฉ๋‹ˆ๋‹ค. ํ•˜์œ„ํด๋ž˜์Šค๋Š” ๊ธฐ์ดˆํด๋ž˜์Šค์—์„œ ์ƒ์†ํ•˜๋Š” ๊ฒƒ ์™ธ์—๋Š” ๊ด€๋ จ์ด ์žˆ์„ ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด:

class Control {
    private state: any;
}

interface SelectableControl extends Control {
    select(): void;
}

class Button extends Control implements SelectableControl {
    select() { }
}

class TextBox extends Control {
    select() { }
}

// Error: Property 'state' is missing in type 'Image'.
class Image implements SelectableControl {
    private state: any;
    select() { }
}

class Location {

}

์œ„ ์˜ˆ์ œ์—์„œ, SelectableControl์€ private state ํ”„๋กœํผํ‹ฐ๋ฅผ ํฌํ•จํ•˜์—ฌ, Control์˜ ๋ชจ๋“  ๋ฉค๋ฒ„๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. state๋Š” private ๋ฉค๋ฒ„์ด๊ธฐ ๋•Œ๋ฌธ์—, SelectableControl๋ฅผ ๊ตฌํ˜„ํ•˜๋Š” ๊ฒƒ์€ Control์˜ ์ž์‹์—๊ฒŒ๋งŒ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค. Control์˜ ์ž์‹๋งŒ ๊ฐ™์€ ์„ ์–ธ์—์„œ ์œ ๋ž˜๋œ state private ๋ฉค๋ฒ„๋ฅผ ๊ฐ€์งˆ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์ด๊ณ , private ๋ฉค๋ฒ„๋“ค์ด ํ˜ธํ™˜๋˜๊ธฐ ์œ„ํ•ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.

Control ํด๋ž˜์Šค ์•ˆ์—์„œ SelectableControl์˜ ์ธ์Šคํ„ด์Šค๋ฅผ ํ†ตํ•ด์„œ state private ๋ฉค๋ฒ„์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. SelectableControl์€ select ๋ฉ”์„œ๋“œ๋ฅผ ๊ฐ€์ง„ Control๊ณผ ๊ฐ™์€ ์—ญํ• ์„ ํ•ฉ๋‹ˆ๋‹ค. Button๊ณผ TextBox ํด๋ž˜์Šค๋“ค์€ SelectableControl์˜ ํ•˜์œ„ํƒ€์ž…์ด์ง€๋งŒ (Control์„ ์ƒ์†๋ฐ›๊ณ , select ๋ฉ”์„œ๋“œ๋ฅผ ๊ฐ€์ง€๊ธฐ ๋•Œ๋ฌธ์—), Image์™€ Location ํด๋ž˜์Šค๋Š” ์•„๋‹™๋‹ˆ๋‹ค.