TypeScript์ ํต์ฌ ์์น ์ค ํ๋๋ ํ์ ๊ฒ์ฌ๊ฐ ๊ฐ์ ํํ์ ์ด์ ์ ๋ง์ถ๊ณ ์๋ค๋ ๊ฒ์ ๋๋ค. ์ด๋ฅผ "๋ ํ์ดํ(duck typing)" ํน์ "๊ตฌ์กฐ์ ์๋ธํ์ดํ (structural subtyping)"์ด๋ผ๊ณ ๋ ํฉ๋๋ค. TypeScript์์, ์ธํฐํ์ด์ค๋ ์ด๋ฐ ํ์ ๋ค์ ์ด๋ฆ์ ์ง๋ ์ญํ ์ ํ๊ณ ์ฝ๋ ์์ ๊ณ์ฝ์ ์ ์ํ๋ ๊ฒ๋ฟ๋ง ์๋๋ผ ํ๋ก์ ํธ ์ธ๋ถ์์ ์ฌ์ฉํ๋ ์ฝ๋์ ๊ณ์ฝ์ ์ ์ํ๋ ๊ฐ๋ ฅํ ๋ฐฉ๋ฒ์ ๋๋ค.
์ด๋ป๊ฒ ์ธํฐํ์ด์ค๊ฐ ๋์ํ๋์ง ํ์ธํ๋ ๊ฐ์ฅ ์ฌ์ด ๋ฐฉ๋ฒ์ ๊ฐ๋จํ ์์ ๋ก ์์ํ๋ ๊ฒ์ ๋๋ค:
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
์ ์ ๋ฌํ ๊ฐ์ฒด๊ฐ ์ด ์ธํฐํ์ด์ค๋ฅผ ๊ตฌํํด์ผ ํ๋ค๊ณ ๋ช
์์ ์ผ๋ก ์๊ธฐํ ํ์๋ ์์ต๋๋ค.
์ฌ๊ธฐ์ ์ค์ํ ๊ฒ์ ํํ๋ฟ์
๋๋ค. ํจ์์ ์ ๋ฌ๋ ๊ฐ์ฒด๊ฐ ๋์ด๋ ์๊ตฌ ์กฐ๊ฑด์ ์ถฉ์กฑํ๋ฉด, ํ์ฉ๋ฉ๋๋ค.
ํ์ ๊ฒ์ฌ๋ ํ๋กํผํฐ๋ค์ ์์๋ฅผ ์๊ตฌํ์ง ์์ต๋๋ค. ๋จ์ง ์ธํฐํ์ด์ค๊ฐ ์๊ตฌํ๋ ํ๋กํผํฐ๋ค์ด ์กด์ฌํ๋์ง์ ํ๋กํผํฐ๋ค์ด ์๊ตฌํ๋ ํ์ ์ ๊ฐ์ก๋์ง๋ง์ ํ์ธํฉ๋๋ค.
์ธํฐํ์ด์ค์ ๋ชจ๋ ํ๋กํผํฐ๊ฐ ํ์ํ ๊ฒ์ ์๋๋๋ค. ์ด๋ค ์กฐ๊ฑด์์๋ง ์กด์ฌํ๊ฑฐ๋ ์์ ์์ ์๋ ์์ต๋๋ค. ์ ํ์ ํ๋กํผํฐ๋ค์ ๊ฐ์ฒด ์์ ๋ช ๊ฐ์ ํ๋กํผํฐ๋ง ์ฑ์ ํจ์์ ์ ๋ฌํ๋ "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
๋ฅผ ๋ฃ์ด์ ์ด๋ฅผ ์ง์ ํ ์ ์์ต๋๋ค:
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
์ const
์ค์ ์ด๋ค ๊ฒ์ ์ฌ์ฉํ ์ง ๊ธฐ์ตํ๊ธฐ ๊ฐ์ฅ ์ฌ์ด ๋ฐฉ๋ฒ์ ๋ณ์์ ํ๋กํผํฐ์ค ์ด๋์ ์ฌ์ฉํ ์ง ์ง๋ฌธํด ๋ณด๋ ๊ฒ์
๋๋ค.
๋ณ์๋ const
๋ฅผ ์ฌ์ฉํ๊ณ ํ๋กํผํฐ๋ readonly
๋ฅผ ์ฌ์ฉํฉ๋๋ค
์ธํฐํ์ด์ค์ ์ฒซ ๋ฒ์งธ ์์ ์์ 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
๊ฐ ์ด๋ฅผ ๋ฐ์ํ๋๋ก ์ ์๋ฅผ ์์ ํด์ผ ํฉ๋๋ค.
์ธํฐํ์ด์ค๋ 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";
};
์ธํฐํ์ด์ค๋ก ํจ์ ํ์
์ ์ค๋ช
ํ๋ ๋ฐฉ๋ฒ๊ณผ ์ ์ฌํ๊ฒ, 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]
์ ๊ฐ์ ํ ๋นํ ์ ์์ต๋๋ค.
ํด๋์ค๊ฐ ํน์ ๊ณ์ฝ(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");
}
}
ํด๋์ค์ฒ๋ผ, ์ธํฐํ์ด์ค๋ค๋ ํ์ฅ(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;
์ผ์ฐ์ด ์ธ๊ธํ๋ฏ์ด, ์ธํฐํ์ด์ค๋ ์ค์ 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์ ์ํธ์์ฉํ ๋, ํ์ ์ ํํ๋ฅผ ์์ ํ ๊ธฐ์ ํ๊ธฐ ์ํด ์์ ๊ฐ์ ํจํด์ ์ฌ์ฉํด์ผํ ์๋ ์์ต๋๋ค.
์ธํฐํ์ด์ค ํ์ ์ด ํด๋์ค ํ์ ์ ํ์ฅํ๋ฉด, ํด๋์ค์ ๋ฉค๋ฒ๋ ์์๋ฐ์ง๋ง ๊ตฌํ์ ์์๋ฐ์ง ์์ต๋๋ค. ์ด๊ฒ์ ์ธํฐํ์ด์ค๊ฐ ๊ตฌํ์ ์ ๊ณตํ์ง ์๊ณ , ํด๋์ค์ ๋ฉค๋ฒ ๋ชจ๋๋ฅผ ์ ์ธํ ๊ฒ๊ณผ ๋ง์ฐฌ๊ฐ์ง์ ๋๋ค. ์ธํฐํ์ด์ค๋ ์ฌ์ง์ด ๊ธฐ์ด ํด๋์ค์ 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
ํด๋์ค๋ ์๋๋๋ค.