๋ณธ ํฌ์คํ ์์ ๋ฏธ๋ฆฌ๋ณด๊ธฐ
1. ํ์ ์คํฌ๋ฆฝํธ ํ๋ก๊ทธ๋๋ฐ ์์ ๋ด๊ฐ ํ์ด๋ณธ ๊ฒ(ํ ํฌ์ธํธ ๋ฏธ์ค, ์์ง๋ ์์ฑ์์ ํ์ดํ ํจ์ ๋ฐ์๋ค์ด๋๊ฒ ์ด์...)
type TreeNode = {
value: string;
};
type LeafNode = TreeNode & {
isLeaf: true;
};
type InnerNode = TreeNode & {
children: [TreeNode] | [TreeNode, TreeNode];
};
let a: TreeNode = { value: "a" }; //ํต๊ณผ
let b: LeafNode = { value: "b", isLeaf: true }; //ํต๊ณผ
let c: InnerNode = { value: "c", children: [b] }; //ํต๊ณผ
let a1 = mapNode(a, (_) => _.toUpperCase()); //TreeNode
let b1 = mapNode(b, (_) => _.toUpperCase()); //LeafNode
let c1 = mapNode(c, (_) => _.toUpperCase()); //InnerNode
function mapNode<T extends TreeNode>(node: T, f: (value: string) => string): T {
return {
...node,
value: node.value.toUpperCase(),
};
}
console.log(a1.value); //A
console.log(b1.value); //B
console.log(c1.value); //C
2. ํ์ ์คํฌ๋ฆฝํธ ํ๋ก๊ทธ๋๋ฐ ์ฑ ๋ชจ๋ฒ๋ต์
type TreeNode = {
value: string;
};
type LeafNode = TreeNode & {
isLeaf: true;
};
type InnerNode = TreeNode & {
children: [TreeNode] | [TreeNode, TreeNode];
};
let a: TreeNode = { value: "a" }; //ํต๊ณผ
let b: LeafNode = { value: "b", isLeaf: true }; //ํต๊ณผ
let c: InnerNode = { value: "c", children: [b] }; //ํต๊ณผ
let a1 = mapNode(a, (_) => _.toUpperCase()); //TreeNode
let b1 = mapNode(b, (_) => _.toUpperCase()); //LeafNode
let c1 = mapNode(c, (_) => _.toUpperCase()); //InnerNode
function mapNode<T extends TreeNode>(node: T, f: (value: string) => string): T {
return {
...node,
value: f(node.value),
};
}
console.log(a1.value); //A
console.log(b1.value); //B
console.log(c1.value); //C
์ ๋ค๋ฆญ ํ์
T๋ฅผ ์ฌ์ฉ ์ค์ผ๋์ ์ ํํ๊ฒ T์ ๊ฐ์ ํ์
์์ ํํํ๊ธฐ๋ณด๋ค๋
”์ด ํ์
์ U ํ์
์ด๊ณ , ์ ์ด๋ T ํ์
์ ํฌํจํ๊ณ ์์ด” ๊ฐ์ ์ํฉ์ด ํ์ํ ๋๊ฐ ์๋ค.
์ด๋ฐ ์ํฉ์ ‘U๊ฐ T์ ์ํ ํ๊ณ(upper bound)’ ๋ผ๊ณ ํ๋ค.
์ด๋ฐ ๊ธฐ๋ฅ์ด ์ ํ์ํ์ง ์ด์ง ํธ๋ฆฌ ์์ ๋ฅผ ์ดํด๋ณธ๋ค.
์ธ ์ข ๋ฅ ๋ ธ๋๋ฅผ ๊ฐ๋ ์ด์งํธ๋ฆฌ๋ฅผ ๊ตฌํํ๋ค๊ณ ๊ฐ์ ํ๋ค.
1. ์ผ๋ฐ TreeNode
2. ์์์ ๊ฐ์ง ์๋ TreeNode์ธ LeafNode
3. ์์์ ๊ฐ๋ TreeNode์ธ InnerNode
๋ฐฐ๊ฒฝ ์ง์: - ์ด์งํธ๋ฆฌ๋ ์๋ฃ๊ตฌ์กฐ๋ค. - ์ด์งํธ๋ฆฌ๋ ๋ ธ๋๋ฅผ ๊ฐ๋๋ค. - ๋ ธ๋๋ ๊ฐ์ ๊ฐ์ง๋ฉฐ ์ต๋ ๋ ๊ฐ์ ์์ ๋ ธ๋๋ฅผ ๊ฐ๋ฆฌํฌ ์ ์๋ค - ๋ ธ๋๋ ์๋ ธ๋(์์์์) ๋๋ ๋ด๋ถ ๋ ธ๋(์ ์ด๋ ํ ๊ฐ์ ์์์ ๊ฐ์ง) ๋ ์ค ํ๋์ ํ์ ์ ๊ฐ๋๋ค. |
๋จผ์ ๊ฐ ๋ ธ๋์ ํ์ ์ ์ ์ธํ๋ค.
//value๋ผ๋ ํ ๊ฐ์ ํ๋กํผํฐ๋ง ๊ฐ๋ ๊ฐ์ฒด
type TreeNode = {
value: string;
};
//TreeNode๊ฐ ๊ฐ๋ ๋ชจ๋ ํ๋กํผํฐ ๋ฟ ์๋๋ผ ๊ฐ์ด ํญ์ true์ธ isLeaf ํ๋กํผํฐ๋ฅผ ์ถ๊ฐ๋ก ํฌํจ
type LeafNode = TreeNode & {
isLeaf: true;
};
//TreeNode๊ฐ ๊ฐ๋ ๋ชจ๋ ํ๋กํผํฐ ๋ฟ ์๋๋ผ ํ ๊ฐ๋ ๋ ๊ฐ์ ์์์ ๊ฐ๋ฆฌํฌ ์ ์๋ children
//ํ๋กํผํฐ๋ฅผ ์ถ๊ฐ๋ก ํฌํจ
type InnerNode = TreeNode & {
children: [TreeNode] | [TreeNode, TreeNode];
};
๋ค์์ผ๋ก TreeNode๋ฅผ ์ธ์๋ก ๋ฐ์ value์ ๋งคํ ํจ์๋ฅผ ์ ์ฉํด ์๋ก์ด Tree Node๋ฅผ ๋ฐํํ๋ mapNode ํจ์๋ฅผ ๊ตฌํํด๋ณธ๋ค.
๋ค์์ฒ๋ผ ์ฌ์ฉํ ์ ์๋ Node ํจ์๊ฐ ํ์ํ๋ค๊ณ ํด๋ณด์.
let a: TreeNode = { value: "a" };
let b: LeafNode = { value: "b", isLeaf: true };
let c: InnerNode = { value: "c", children: [b] };
let a1 = mapNode(a, (_) => _.toUpperCase()); //TreeNode
let b1 = mapNode(b, (_) => _.toUpperCase()); //LeafNode
let c1 = mapNode(c, (_) => _.toUpperCase()); //InnerNode
TreeNode์ ์๋ธํ์ ์ ์ธ์๋ก ๋ฐ์ ๊ฐ์ ์๋ธํ์ ์ mapNode ํจ์๋ฅผ ๊ตฌํ
(LeafNode๋ฅผ ์ ๋ฌํ๋ฉด LeafNode ๋ฐํ, InnerNode๋ฅผ ์ ๋ฌํ๋ฉด InnerNode๊ฐ ๋ฐํ๋๋ฉฐ, TreeNode๋ฅผ ์ ๋ฌํ๋ฉด TreeNode๊ฐ ๋ฐํ
function mapNode<T extends TreeNode>(node: T, f: (value: string) => string): T {
return {
...node,
value: f(node.value),
};
}
<์ง๊ธ๊น์ง ์ ์ฒด ์ฝ๋>
type TreeNode = {
value: string;
};
type LeafNode = TreeNode & {
isLeaf: true;
};
type InnerNode = TreeNode & {
children: [TreeNode] | [TreeNode, TreeNode];
};
let a: TreeNode = { value: "a" };
let b: LeafNode = { value: "b", isLeaf: true };
let c: InnerNode = { value: "c", children: [b] };
let a1 = mapNode(a, (_) => _.toUpperCase()); //TreeNode
let b1 = mapNode(b, (_) => _.toUpperCase()); //LeafNode
let c1 = mapNode(c, (_) => _.toUpperCase()); //InnerNode
function mapNode<T extends TreeNode>(node: T, f: (value: string) => string): T {
return {
...node,
value: f(node.value),
};
}
1. mapNode๋ ํ ๊ฐ์ ์ ๋ค๋ฆญ ํ์ ๋งค๊ฐ๋ณ์ T๋ฅผ ์ ์ํ๋ ํจ์. T์ ์ํ ๊ฒฝ๊ณ๋ TreeNode.
(์ฆ, T๋ TreeNode ์ด๊ฑฐ๋ ์๋๋ฉด TreeNode์ ์๋ธํ์ )
function mapNode<T extends TreeNode>
T ์๋ฆฌ์ (๋น๊ฐ์ฒด{}, null, TreeNode ๋ฐฐ์ด ๋ฑ์) TreeNode๊ฐ ์๋ ๋ค๋ฅธ ๊ฒ์ ์ธ์๋ก ์ ๋ฌํ๋ฉด ๋ฐ๋ก ๊ผฌ๋ถ๊ฑฐ๋ฆฌ๋ ๋นจ๊ฐ ๋ฐ์ค.
์ T๋ฅผ ์ด๋ฐ ๋ฐฉ์์ผ๋ก ์ ์ธํ๋๋ฉด,
extends TreeNode๋ฅผ ์๋ตํ๊ณ Tํ์ ์ ๊ทธ์ T๋ผ๊ณ ๋ง ์ฐ๋ฉด (ํน์ ํ์ ๊ณผ ์ฐ๊ฒฐ๋์ง ์์) mapNode๊ฐ ์ปดํ์ผ ํ์ ์๋ฌ๋ฅผ ๋์ง ๊ฒ์ด๋ค. T ํ์ ์ ์ํ ๊ฒฝ๊ณ๊ฐ ์์ผ๋ฏ๋ก node.value๋ฅผ ์ฝ๋ ํ์๊ฐ ์์ ํ์ง ์๊ธฐ ๋๋ฌธ(์๋ฅผ ๋ค์ด ์ซ์๊ฐ ๊ฑด๋ค์ง ์๋ ์๋ค.)
T๋ฅผ ์์ ์ฌ์ฉํ์ง ์๊ณ mapNode๋ฅผ (node: TreeNode, f:(value:string)=>string) =>TreeNode์ฒ๋ผ ์ ์ธํ๋ฉด ๋งคํ๋๋ฉด์ ํ์ ์ ๋ณด๊ฐ ๋ ์๊ฐ์ a1, b1, c1์ด ๋ชจ๋ TreeNode๊ฐ ๋๋ค.
T extends TreeNode๋ผ๊ณ ํํํจ์ผ๋ก์จ ๋งคํํ ์ดํ์๋ ์ ๋ ฅ ๋ ธ๋๊ฐ ํน์ ํ์ (TreeNode, LeafNode, InnerNode)์ด๋ผ๋ ์ ๋ณด๋ฅผ ๋ณด์กดํ ์ ์๋ค.
<๋ชจ๋ฒ>
value: string;
};
type LeafNode = TreeNode & {
isLeaf: true;
};
type InnerNode = TreeNode & {
children: [TreeNode] | [TreeNode, TreeNode];
};
let a: TreeNode = { value: "a" }; //ํต๊ณผ
let b: LeafNode = { value: "b", isLeaf: true }; //ํต๊ณผ
let c: InnerNode = { value: "c", children: [b] }; //ํต๊ณผ
let a1 = mapNode(a, (_) => _.toUpperCase()); //TreeNode
let b1 = mapNode(b, (_) => _.toUpperCase()); //LeafNode
let c1 = mapNode(c, (_) => _.toUpperCase()); //InnerNode
function mapNode<T extends TreeNode>(node: T, f: (value: string) => string): T {
return {
...node,
value: f(node.value),
};
}
console.log(a1); //{ value: 'A' }
console.log(b1); //{ value: 'B', isLeaf: true }
console.log(c1); //{ value: 'C', children: [ { value: 'b', isLeaf: true } ] }
์ฌ๋ฌ ์ ํ์ ์ ์ฉํ ํ์ ๋ ๋คํ์ฑ
์์ ์์์๋ T๋ ์ ์ด๋ TreeNode์ฌ์ผ ํ๋ค๋ ํ์ ์ ํ์ ํ๋ ์ถ๊ฐํ๋ค.
์ฌ๋ฌ ๊ฐ๋ฅผ ์ถ๊ฐํ๋ ค๋ฉด ๋จ์ํ ์ธํฐ์น์ (&)์ผ๋ก ์ ํ๋ค์ ์ด์ด๋ถ์ด๋ฉด ๋๋ค.
type HasSides = { numberOfSides: number };
type SidesHaveLength = { sideLength: number };
function logPerimeter<T extends HasSides & SidesHaveLength>(s: T): T {
console.log(s.numberOfSides * s.sideLength);
return s;
}
type Square = HasSides & SidesHaveLength;
let square: Square = { numberOfSides: 4, sideLength: 3 };
logPerimeter(square);
logPerimeter์ Shape ํ์ ์ ์ธ์ s ํ ๊ฐ๋ฅผ ์ธ์๋ก ๋ฐ๋ ํจ์๋ค.
Shape๋ HasSides ํ์ ๊ณผ SideHaveLength ํ์ ์ ์์๋ฐ๋ ์ ๋ค๋ฆญ ํ์ ์ด๋ค. ์ฆ, Shape๋ ์ ์ด๋ ๊ธธ์ด(length)๋ฅผ ๊ฐ๋ ๋ณ(side)๋ค๋ก ์ด๋ฃจ์ด์ง๋ค.
logPerimeter๋ ์ธ์์ ํ์ ์ด ๊ฐ์ ๊ฐ์ ๋ฐํํ๋ค.
์ ๋ค๋ฆญ | ํ์ ์คํฌ๋ฆฝํธ ํธ๋๋ถ
์ ๋ค๋ฆญ(Generics)์ ์ฌ์ ์ ์ ์ ์ ๋ค๋ฆญ์ C#, Java ๋ฑ์ ์ธ์ด์์ ์ฌ์ฌ์ฉ์ฑ์ด ๋์ ์ปดํฌ๋ํธ๋ฅผ ๋ง๋ค ๋ ์์ฃผ ํ์ฉ๋๋ ํน์ง์ ๋๋ค. ํนํ, ํ๊ฐ์ง ํ์ ๋ณด๋ค ์ฌ๋ฌ ๊ฐ์ง ํ์ ์์ ๋์ํ๋ ์ปดํฌ๋ํธ๋ฅผ
joshua1988.github.io
์ ๋ค๋ฆญ ์ ์ฝ ์กฐ๊ฑด
์ ๋ค๋ฆญ ํจ์์ ์ด๋ ์ ๋ ํ์ ํํธ๋ฅผ ์ค ์ ์๋ ๋ฐฉ๋ฒ
function logText<T>(text: T): T {
console.log(text.length); // Error: T doesn't have .length
return text;
}
์ธ์์ ํ์ ์ ์ ์ธํ T๋ ์์ง ์ด๋ค ํ์ ์ธ์ง ๊ตฌ์ฒด์ ์ผ๋ก ์ ์ํ์ง ์์๊ธฐ ๋๋ฌธ์ length ์ฝ๋์์ ์ค๋ฅ
ํด๋น ํ์ ์ ์ ์ํ์ง ์๊ณ ๋ length ์์ฑ ์ ๋๋ ํ์ฉํ๋ ค๋ฉด ์๋์ ๊ฐ์ด ์์ฑ
interface LengthWise {
length: number;
}
function logText<T extends LengthWise>(text: T): T {
console.log(text.length);
return text;
}
์์ ๊ฐ์ด ์์ฑํ๊ฒ ๋๋ฉด ํ์ ์ ๋ํ ๊ฐ์ ๋ ์๋์ง๋ง length์ ๋ํด ๋์ํ๋ ์ธ์๋ง ๋๊ฒจ๋ฐ์ ์ ์๊ฒ ๋๋ค.
logText(10); // Error, ์ซ์ ํ์
์๋ `length`๊ฐ ์กด์ฌํ์ง ์์ผ๋ฏ๋ก ์ค๋ฅ ๋ฐ์
logText({ length: 0, value: 'hi' }); // `text.length` ์ฝ๋๋ ๊ฐ์ฒด์ ์์ฑ ์ ๊ทผ๊ณผ ๊ฐ์ด ๋์ํ๋ฏ๋ก ์ค๋ฅ ์์
๊ฐ์ฒด์ ์์ฑ์ ์ ์ฝํ๋ ๋ฐฉ๋ฒ
๋ ๊ฐ์ฒด๋ฅผ ๋น๊ตํ ๋๋ ์ ๋ค๋ฆญ ์ ์ฝ ์กฐ๊ฑด์ ์ฌ์ฉํ ์ ์๋ค.
function getProperty<T, O extends keyof T>(obj: T, key: O) {
return obj[key];
}
let obj = { a: 1, b: 2, c: 3 };
getProperty(obj, "a"); // okay
getProperty(obj, "z"); // error: "z"๋ "a", "b", "c" ์์ฑ์ ํด๋นํ์ง ์์ต๋๋ค.
์ ๋ค๋ฆญ์ ์ ์ธํ ๋ <O extends keyof T> ๋ถ๋ถ์์ ์ฒซ ๋ฒ์งธ ์ธ์๋ก ๋ฐ๋ ๊ฐ์ฒด์ ์๋ ์์ฑ๋ค์ ์ ๊ทผํ ์ ์๊ฒ๋ ์ ํ
typescript - ํ์ ๋ณ์นญ (type-aliases)
typescript - ํ์ ๋ณ์นญ (type-aliases), ํ์ ์คํฌ๋ฆฝํธ, ts
kyounghwan01.github.io
ํ์ ๋ณ์นญ
ํ์ ๋ณ์นญ์ ์ธํฐํ์ด์ค์ ๊ฑฐ์ ๋น์ทํ ๊ธฐ๋ฅ
๊ฐ์ฒด ๋๋ ํจ์์ ๋ํ ํ์ ์ ์๋ฅผ ํ๋ ์ผ.
type Developer = {
name: string;
skill: string;
};
ํ์ ๋ณ์นญ์๋ ์ ๋ค๋ฆญ ์ฌ์ฉ ๊ฐ๋ฅ
type typeGeneric<T> = {
name: T;
};
ํ์
๋ณ์นญ์ ์๋ก์ด ํ์
๊ฐ์ ํ๋ ์์ฑํ๋ ๊ฒ์ด ์๋๋ผ ์ ์ํ ํ์
์ ๋ํด ๊ฐ๋ฐ์๊ฐ ์ฝ๊ฒ ๊ด์ฐฐํ๋๋ก ์ด๋ฆ์ ๋ถ์ฌ
๊ทธ๋์ interface๋ฅผ ์ ์ํ๊ณ ์ปค์๋ฅผ hoverํ๋ฉด interface xx ์ด๋ ๊ฒ ๋์ค์ง๋ง type์ type xx = {xx: xx}
์ธํฐ์น์ ์ ์ํ ํ์ฅ
ํ์ ๋ณ์นญ์ extends๋ผ๋ ๋ช ๋ น์ด๊ฐ ์๊ณ ์ธํฐ์น์ (&)๋ฅผ ์ด์ฉํด ํ์ฅํ๋ค.
type test1 = { name: string };
type test2 = test1 & { age: number };
const test3: test2 = { name: "d", age: 33 };
์ ๋ฐฉ๋ฒ์ ์๋ฐํ ๋ฐ์ง๋ฉด ์ธํฐ์น์ ์ ์ด์ฉํ์ฌ test1 ํ์ ๊ณผ ์ถ๊ฐ๋ ํ์ ์ ํฉํ์ฌ ์๋ก์ด ํ์ ์ ์ ์ํ ๊ฒ์ด์ง test1 ํ์ ์ extends๋ก ์์ ๋ฐ์ ํ์ฅํ๋ ๊ฐ๋ ์ด ์๋๋ค. ๊ทธ๋ฌ๋ฏ๋ก type์ extend๊ฐ ์๋๊ธฐ ๋๋ฌธ์ ์ ๋งํ๋ฉด interface๋ฅผ ์ฐ๋๋ก ํ์.