또한 제네릭 타입 뒤에 extends 타입을 넣으면 구조는 모르지만 해당 타입이라는건 명시할 수 있다
이렇게 하면 반환 값의 타입도 알 수 있게 되어(매개변수 타입이 명확해졌으니)
타입에는 object, string 등이 들어갈 수 있다
extends를 하면 타입이 명확해져서, 특정 타입에서만 쓸 수 있는 함수를 쓸 수 있다
즉, 이 함수의 매개변수와 반환값이 정확히 어떤 타입인진 몰라도 대략적인 타입은 알 수 있다
ex) 객체 속성들이 어떤 타입인지까지는 몰라도, 객체인건 안다
function merge<T, U>(obj1: T, obj2: U) {
//매개변수 타입을 T,U로 두어(아무거나 둬도 됨) 두 매개변수의 타입이 다르다는 것을 명시
return ..
}
const mergedObj = merge({name: "a"}, {age: 12})
//T는 {name: string} 타입의 객체, U는 {age: number} 타입의 객체라고 정의
//extends
function merge2<T extends object, U extends object>(a: T, b: U) {
return Object.assign(a,b)
//두 객체의 합집합인 새로운 객체 반환 => 둘 다 객체일 때만 쓸 수 있는 함수를 사용 가능
// 이로써 반환값도 (속성이 무엇이든) 두개의 합집합이라는 것이 정해졌음
}
const mergedObj = merge2({name: "a"}, {age: 12})
직접만든객체나 인터페이스를 extends한다면 extend한 객체나 인터페이스의 속성만 들어가있으면 된다.
interface Lengthy {
length: number;
}
function countAndDescribe<T extends Lengthy>(element: T) {
//element는 length를 속성으로 가지고 있는 객체여야 한다
if(element.length === 1) {
..
}
}
countAndDescribe('Hi there!')
// 사실 JS뒷단에서 string을 객체로 변환한다. 그리고 여기에는 length라는 속성이 있다
// 어쨌든 그래서, string도 T가 될 수 있다
keyof 제약 조건
(only TS) 제네릭 T가 객체라면, 이것의 key를 keyof로 표현할 수 있다
keyof 타입 연산자 : 뒤에 딸려오는 객체의 key들을 유니언한 것이다
ex) type Point = { x: number; y: string } 일 때, keyof Point는 “x” | “y”