12. ๐ฆ TypeScript - ์ต์ ๋(Optional) & ์ ๋ค๋ฆญ(Generic) ์ ๋ฆฌ
๐ 1. ์ต์ ๋(Optional)
โ ์ฌ์ฉ ๋ฐฉ๋ฒ
- ?๋ ํญ์ ์์ฑ๋ช ๋๋ ๋งค๊ฐ๋ณ์ ์ด๋ฆ ๋ค์ ๋ถ์ ๋๋ค.
- ์กด์ฌํด๋ ๋๊ณ , ์์ด๋ ๋๋ ๊ฐ์ ์๋ฏธํฉ๋๋ค.
โ ํจ์ ๋งค๊ฐ๋ณ์์์ ์ต์ ๋ ์ฌ์ฉ
function abc(a: number, b?: number, c?: number) {}
abc(1); // ์ ๋ถ ๊ฐ๋ฅํ๋ค
abc(1, 2); // ์ ๋ถ ๊ฐ๋ฅํ๋ค
abc(1, 2, 3); // ์ ๋ถ ๊ฐ๋ฅํ๋ค
โ ์ฃผ์: ์ต์ ๋ ๋งค๊ฐ๋ณ์๋ ๋ง์ง๋ง์ ๋ฐฐ์นํ๋ ๊ฒ์ด ์ข์ต๋๋ค.
โ ๋๋จธ์ง ๋งค๊ฐ๋ณ์(rest parameter)
// ์ ํ์์ด ์
๋ ฅ์ ๋ฐ๊ณ ์ถ์ ๊ฒฝ์ฐ
function abc(...args: number[]) {}
abc(1, 2, 3, 4);
โ type alias์์ ์ต์ ๋
// type alias์์ ์ต์
๋ ์ฌ์ฉ
type User = {
id: number;
nickname?: string; // ์์ด๋ ๋๊ณ ์์ด๋ ๋จ
};
const u1: User = { id: 1 };
const u2: User = { id: 2, nickname: "sunbin" };
โ interface์์ ์ต์ ๋
// interface์ ์ต์
๋ ์ฌ์ฉ
interface Product {
name: string;
price?: number;
}
const p1: Product = { name: "Book" };
const p2: Product = { name: "Bag", price: 50 };
โ ํด๋์ค์์ ์ต์ ๋ ์์ฑ
class Person {
name: string;
age?: number;
constructor(name: string, age?: number) {
this.name = name;
if (age !== undefined) {
this.age = age;
}
}
}
let obj: { a: string; b?: string } = { a: "hello", b: "world" };
obj = { a: "hello" }; // b๊ฐ ์์ด๋ ๊ทธ๋ง ์์ด๋ ๊ทธ๋ง,
๐ 2. ์ ๋ค๋ฆญ (Generic)
โ ๊ฐ๋
์ ๋ค๋ฆญ์ด๋ ํ์ ์ ๋งค๊ฐ๋ณ์์ฒ๋ผ ์ ๋ฌ๋ฐ์ ์ฌ์ฉํ๋ ๋ฐฉ์์ ๋๋ค.
โ ์ ๋๋ฆญ์ ์ฌ์ฉํ๋ ์ด์
function add(x: string | number, y: string | number): string | number {
return x + y;
}
// ํ์
์คํฌ๋ฆฝํธ๋ ๋ชจ๋ ๊ฒฝ์ฐ๋ฅผ ๋ค ๊ณ ๋ คํ๊ธฐ ๋๋ฌธ์ 2 * 2์ ๋ชจ๋ ์ํฉ์ ๊ณ ๋ ค
// ๊ฒฐ๊ณผ๋ฅผ ์ด๋ ๊ฒ ๋ง๋ค๊ฒ์ผ๋ก ์๊ฐ ํ๊ณ ๋ง๋ค์์ง๋ง,
add(1, 2); // 3
add("1", "2"); //12
// ์ด๋ฐ ๋ชจ๋ ์ผ์ด์ค๋ค์ ๋ํด์๋ ๊ณ ๋ คํ๊ธฐ ๋๋ฌธ์ ์ฌ๋ฐ๋ฅธ ํจ์๋ผ๊ณ ๋ณผ ์ ์์
add(1, "2"); //12
add("1", 2); //12
ํ๋์ ํจ์ ๋ช ์ผ๋ก ๋๊ฐ์ง ๊ธฐ๋ฅ์ ๋์์ ์ฒ๋ฆฌํ๋๋ก ํ๊ณ ์ถ์ง๋ง, ๋ค์๊ณผ ๊ฐ์ ๋ฐฉ๋ฒ์ผ๋ก๋ ์ฒ๋ฆฌ ํ ์ ์์
// ๋์ผํ ๊ฐฏ์์ ๋งค๊ฐ๋ณ์๋ ์ค๋ฒ ๋ก๋ฉ ๋ถ๊ฐ๋ฅ
function add(x: string, y: string): string;
function add(x: number, y: number): number;
โ ๊ธฐ๋ณธ ์์
// ์ ๋๋ฆญ
// ๋์ผ ํ์
์ ์ฌ์ฉํ๊ณ ,
// T๋ผ๊ณ ํ๊ธฐํด ๋์์ง๋ง, ์ด๋ค ๋ฌธ์๋ก๋ ๋ค ๊ธฐ์
๊ฐ๋ฅํ๋ค.
function add<T>(x: T, y: T): T {
return x + y;
}
// ์ ๋๋ฆญ์ ํจ์๋ฅผ ์ฌ์ฉํ ๋ ํ์
์ด ์ ํด์ง ์ ์๊ฒ ์ฌ์ฉํ๋ค.
add(1, 2);
add("1", "2");
add<number>(1, 2);
add<string>("1", "2");
// ์ฌ์ ํ ์ค๋ฅ
// add(1, "2") // โ ํ์
๋ถ์ผ์น ์๋ฌ
โ ํ์ ์ ํ (extends)
// ๋ฒ์๊ฐ ๋๋ฌด ๋๋ค๊ณ ํ๋จ๋ ๊ฒฝ์ฐ, T์ ์ ํ์ ๋์ ์๋ค.
function add<T extends string>(x: T, y: T): T {
return x + y;
}
// ๋งค๊ฐ๋ณ์ ๋ง์ ๊ฐ์ ํ์
์ด ๋ค์ด๊ฐ ์ ์๋๋ก ํ ์ ์๋ค.
function add<T extends string | number>(x: T, y: T): T {
return x + y;
}
// ์ฌ๋ฌ ๊ฐ์ ์ ๋๋ฆญ๋ ์ฌ์ฉ ๊ฐ๋ฅํ๋ค.
function add<T extends string | number, K extends string>(x: T, y: T): T {
return x + y;
}
โ ์ ๋ค๋ฆญ ์ ์ธ ์์น ๊ธฐ์ตํ๊ธฐ
function a<T>() {}
class B<T>() {}
interface C<T> {}
type D<T> = {};
const e = <T>() => {};
๐ 3. ์ ๋ค๋ฆญ ๋ค์ํ ํ์ฉ ์์
โ 1 - ๊ฐ์ฒด ํ์ ์ ์ฝ
// ํน์ ๊ฐ์ฒด
// <T extends {...}>
function printA<T extends { a: string }>(obj: T): void {
// โ
TypeScript only: obj must have string `a`
console.log(obj.a);
}
printA({ a: "hello" }); // โ
OK
printA({ a: "world", extra: 123 }); // โ
OK
// printA({ b: "oops" }); // โ TS error: a๊ฐ ์์
โ 2 - ๋ฐฐ์ด ํ์ ์ ์ฝ
// ๋ชจ๋ ๋ฐฐ์ด
// <T extends any[]>
function getList<T extends string[]>(x: T): T {
return x;
}
getList(["1", "2", "3"]);
function getFirst<T extends any[]>(arr: T): T[number] {
// โ
TypeScript only: ๋ฐฐ์ด์ ์์ ํ์
์ ์๋ ์ถ๋ก ํจ
return arr[0];
}
const x = getFirst(["a", "b"]); // string ์ถ๋ก ๋จ
const y = getFirst([1, 2, 3]); // number ์ถ๋ก ๋จ
โ 3 - ํจ์ ํ์ ์ ์ฝ
// ํจ์ ํ์
// <T extends (...args: any) => any> // ๋ชจ๋ ํจ์
// (...args: any) => any ๋ชจ๋ ํจ์ ์
๋ ฅ (any๋ฅผ ์จ๋ ๋๋ ์ ์ผํ ์์ธ)
// ์
๋ ฅ๋ฐ๋ ์ฝ๋ฐฑ ํจ์์ ํํ๋ฅผ ์ง์ ํ๋ค.
function add<T extends (a: string) => number>(x: T): T {
return x;
}
function useCallback<T extends (...args: any[]) => any>(fn: T): void {
// โ
TypeScript only: fn์ ํจ์ ํ์
์ด์ด์ผ ํจ
fn(); // args ์์ผ๋ฉด undefined๋ก ํธ์ถ๋จ
}
useCallback(() => console.log("hello")); // OK
// ์
๋ ฅ ํํ ๊ณ ์
function runCallback<T extends (msg: string) => void>(fn: T): void {
fn("TypeScript");
}
runCallback((text) => console.log(text.length)); // OK
โ 4 - ์์ฑ์ ํ์ ์ ์ฝ
// ์์ฑ์ ํ์
// <T extends abstract new (...args: any) => any>
function add<T extends abstract new (...args: any) => any>(x: T): T {
return x;
}
// ํด๋์ค ์์ฒด๋ฅผ ๋ฃ๊ณ ์ถ์๋
class A {}
add(A);
add(new A()); // ์ค๋ฅ
function create<T extends abstract new (...args: any[]) => any>(Ctor: T): InstanceType<T> {
// โ
TypeScript only: ์์ฑ์๋ก๋ง ํธ์ถ ๊ฐ๋ฅ
return new Ctor();
}
class MyClass {
msg = "hi";
}
const obj = create(MyClass);
console.log(obj.msg); // "hi"
โ 5 - ํค ํ์ ์ ํ (keyof any)
// <T extends keyof any> // string | number | symbol
// ๋ชจ๋ ํค๋ค์ ๋ฐ๊ณ ์ถ์๋
function logKey<T extends keyof any>(key: T) {
// โ
TypeScript only: ํค ํ์
๋ง ํ์ฉ (string | number | symbol)
console.log(`Key is: ${String(key)}`);
}
logKey("name"); // โ
OK
logKey(42); // โ
OK
logKey(Symbol("id")); // โ
OK
๐ฆ Symbol์ด๋?
Symbol์ ๊ณ ์ ํ๊ณ ์ถฉ๋ํ์ง ์๋ ์๋ณ์๋ฅผ ๋ง๋ค๊ธฐ ์ํ ์์ ํ์ (primitive type)
Symbol์ ํค ์ด๋ฆ ์ถฉ๋์ ๋ฐฉ์งํ ์ ์๊ธฐ ๋๋ฌธ์, ๋ผ์ด๋ธ๋ฌ๋ฆฌ ๋ด๋ถ๋ ๋ฉํ๋ฐ์ดํฐ ๋ฑ์ ์์ฃผ ์ฌ์ฉ๋ฉ๋๋ค.
const sym1 = Symbol("id");
const sym2 = Symbol("id");
console.log(sym1 === sym2); // false โ ์๋ก ๋ค๋ฆ
// ์ฌ์ฉ์์
// ๊ฐ์ฒด ํค๋ก ์ฌ์ฉ:
const id = Symbol("id");
const user = {
name: "sunbin",
[id]: 12345
};
console.log(user[id]); // 12345
Last updated on