ㅇㅇㅈ Blog

프론트엔드 수행중

0%

TS-Generics-Function

Generics

1
2
3
4
5
function hello(message: any) : any {
return message
}
console.log(hello('mark')) // any로 추론되기 때문에 .length 같은 property를 사용하지 못한다
console.log(hello(39))
1
2
3
4
function helloGeneric<T> (message:T) :T { // 함수의 안에서 T의 타입을 기억하게 된다
return message
}
console.log(helloGeneric('Mark'))
1
2
3
4
function helloGeneric<T> (message:T) :T { // 함수의 안에서 T의 타입을 기억하게 된다
return message
}
console.log(helloGeneric(39))
1
2
3
4
function helloGeneric<T> (message:T) :T { // 함수의 안에서 T의 타입을 기억하게 된다
return message
}
console.log(helloGeneric(true))

Generics Basic

1
2
3
4
5
6
7
function helloBasic<T>(message: T): T {
return message
}

helloBasic<string>('hello') // 타입이 string으로 된다
helloBasic(36) // T의 타입을 넣지 않으면 추론된다 36이 number이지만 number가 아닌 가장 좁은 범위인 36으로 추론된다

Generics Array & Tuple

1
2
3
4
5
6
function helloArray<T>(message: T[]): T {
return message[0]
}

helloArray(['Hello', 'World'])
helloArray(['hello', 5])

string으로 추론

string과 number로 추론

사용할 수 있는 메서드가 제한적이다

1
2
3
4
5
function helloTuple<T, K>(message: [T, K]): T {
return message[0]
}
helloTuple(['Hello', 'World'])
helloTuple(['Hello', 5])

Generics Function

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// type alias
type HelloFunctionGeneric1 = <T>(message: T) => T

const hellofunction1: HelloFunctionGeneric1 = <T>(message: T): T => {
return message
}

// interface
interface HelloFunctionGeneric2 {
<T>(message: T): T
}

const helloFunction2: HelloFunctionGeneric2 = <T>(message: T): T => {
return message
}

Generics Class

1
2
3
4
5
6
7
8
9
class Person<T> {
private _name: T

constructor(name: T) {
this._name = name
}
}
const p1 = new Person('Mark')
new Person<string>('123')
1
2
3
4
5
6
7
8
9
10
11
12
class Person<T, K> {
private _name: T
private _age: K

constructor(name: T, age: K) {
this._name = name
this._age = age
}
}

const p1 = new Person(123, 'Mark')
new Person<string, number>('Hello', 123)

Generics with extends

1
2
3
4
5
6
7
8
9
10
11
12
13
class PersonExtends<T extends string | number> {
// T 는 string 과 number만 가능하다
// class 상속과는 조금 다른 개념
private _name: T

constructor(name: T) {
this._name = name
}
}

new PersonExtends('Mark')
new PersonExtends(39)
new PersonExtends(true) // error

keyof & type lookup system

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
interface IPerson {
name: string
age: number
}

const person: IPerson = {
name: 'Mark',
age: 39,
}

type Keys = keyof IPerson

const keys: Keys = 'name'

// IPerson[keyof IPerson]
// => IPerson["name" | "age"]
// => IPerson['name] | IPerson['age']
// => string | number
function getProp<T, K extends keyof T>(obj: T, key: K): T[K] {
return obj[key]
}

getProp(person, 'name')

function setProp<T, K extends keyof T>(obj: T, key: K, value: T[K]): void {
obj[key] = value
}

setProp(person, 'name', 'anna')