- TS는 제네릭을 사용하여 유형 간의 관계를 찾습니다.
- 제네릭 타입 매개변수는 얼마든지 선언할 수 있습니다.
- 유형 매개변수에는 일반적으로 T 또는 U와 같은 한 글자 이름 또는 키 및 값과 같은 Pascal 대소문자 이름이 있습니다.
10.1 일반 함수
- 함수는 매개변수 측면에서 일반화됩니다. ⇒ 함수 내에서 매개변수 유형 주석 및 반환 값 주석으로 사용할 수 있습니다!
function iden<T>(input:T){
return input;
}
const num=iden("me")//타입 me
const stringy=iden(123)//타입 123
//화살표 함수 형태의 제네릭(리액트 환경에서 JSX와 충돌이 있음=>13장에서 다룸)
const iden2=<U>(input:U)=>input;
- 위와 같은 방법으로 어떤 남자다른 입력을 수락하고 형식 안전을 유지합니다.
10.1.1 명시적 일반 호출 유형
- 일반 함수: 함수가 호출되는 방식에 따라 유형 인수를 추론합니다. ⇒ 위 코드에서 TS 검사기는 제공된 인수를 사용하여 식별합니다. ⇒ 매개변수에 대한 유형 인수를 추론합니다!
function logWrapper<Input>(callback:(input:Input)=>void){
return (input:Input)=>{
console.log("Input",input);
callback(input);
}
}
//타입 (input:string)=>void
logWrapper((input:string)=>{
console.log(input.length);
})
//타입:(input:unknown)=>void;
logWrapper((input)=>{
console.log(input.length);//Error: length does not exists on type unknown
})
- TS가 typeX 매개변수를 모르는 경우 입력이 무엇인지 아는 방법
- 명시적 제네릭 형식 인수: 불명으로 설정된 것을 파기하기 위해 ⇒ 일치하는지 확인하기 위해 일반 호출에서 유형 테스트 수행
logWrapper<string>((input)=>{
console.log(input.length);
})
- 위와 같이 지정 가능 문자열 타입으로 지정 가능 ⇒ 필요한 경우에만 지정하는 것이 좋음 (필요시 X 지정)
10.1.2 여러 함수 유형의 매개변수
- 쉼표로 구분된 유형 매개변수의 수에 상관없이 함수를 정의합니다.
function A<First,Second>(first:First,second:Second){
return(first,second)as const;
}
let tuple=A(true,"abc"); //value:readonly (boolean,string) 타입
- 위와 같이 여러 유형 매개변수가 선언되면 둘 다 명시적 제네릭 유형으로 선언되거나 둘 다 X입니다(하나만 파생된 X임).
function make<Key,Value>(key:Key,value:Value){
return {key, value};
}
//ok 타입 둘 다 인수 제공X
make("abc",123); //타입: {key:string,value:number};
//ok 둘 다 타입 제공됨
make<string,number>("abc",123);//타입: {key:string;value:number};
make<"abc",123>("abc",123) //타입: {key:"abc",value:123};
make<string>("abc",123)//한 쪽만 제공X Error 밠애
일반 구조는 하나 이상의 매개변수 사용 X⇒ 코드 가독성 감소
10.2 일반 인터페이스
- 인터페이스에서 제네릭을 선언할 수도 있습니다.
interface Box<T>{
inside:T
}
let stringyBox:Box<string>={
inside:"abc",
}
let numberBox: Box<number>={
inside:123,
}
let incorrectBox:Box<number>={
inside:false, //당연히 타입 에러 발생!
}
- TS의 내장 배열 방법은 Genelec으로 정의됩니다. ⇒ 배열은 유형 매개변수 T를 사용하여 배열에 저장된 데이터 유형을 지정합니다!
10.2.1 파생된 제네릭 인터페이스 유형
- 함수와 동일 ⇒ 인터페이스의 타입 인수는 사용법에서 유추할 수 있습니다!
interface LinkedNode<Value>{
next?:LinkedNode<Value>;
value:Value;
}
function getLast<Value>(node:LinkedNode<Value>):Value{
return node.next? getLast(node.next):node.value;
}
let lastDate=getLast({
value:new Date("09-13-1993")
});
let lastFruit=getLast({
next:{
value:"ban",
},
value:"apple",
})
let lastMismatch=getLast({
next:{
value:123 //여기에서 이미 number로 지정됨!
},
value:false, //Error boolean => number 불가!
})
- 인터페이스 유형 매개변수 ⇒ 유형 주석은 항상 해당 유형 인수를 제공해야 합니다! ⇒ 그렇지 않으면 오류가 발생합니다!
10.3 일반 클래스
- 또한 클래스는 멤버가 사용할 유형 매개변수를 얼마든지 선언할 수 있습니다(클래스의 각 인스턴스에는 유형 매개변수와 다른 유형 인수 세트가 있습니다.)
class Sec<Key,Value>{
key:Key;
value:Value;
constructor(key:Key,value:Value){
this.key=key;
this.value=value;
}
getValue(key:Key):Value|undefined{
return this.key===key?this.value:undefined;
}
}
const storage= new Sec(1234,"abcd"); //타입 Sec<number,string>
storage.getValue(1987);//타입 string | undefined;
10.3.1 명시적 제네릭 클래스 유형
- 인스턴스를 생성할 때 함수 생성자에게 전달된 매개변수의 타입에서 타입을 유추할 수 있다면 ⇒ TS는 타입을 유추(기본값은 알 수 없음)
class Cur<Input>{
#callback:(input:Input)=>void;
constructor(callback:(input:Input)=>void){
this.#callback=(input:Input)=>{
console.log("Input",input);
callback(input);
}
}
call(input:Input){
this.#callback(input);
}
}
//이 경우 Input=string 타입
new Cur((input:string)=>{
console.log(input.length);
})
//타입:unknown이라 에러 발생!
new Cur((input)=>{
console.log(input.length);
})
//명시적 제네릭 클래스 타입
new Cur<string>((input)=>{
console.log(input.length);
})
10.3.2 일반 클래스 확장