let a = "hello"; //이게 더 좋다.
let b :boolean = true;
let c : number[] = [];
// 단, TS가 타입을 추론하지 못할 때는 명시적으로 써주는 것도 유용하다.
const playerNico : {
name: string,
age?:number
} = {
name: "nico"
}
위 코드는 다음과 같이 바꿔볼 수 도 있다.
type Player : {
name: string,
age?: number
}
const playNico :Player = {
name:"nico"
}
if(player.age && player.age <10){
}
함수에서는 이렇게 사용한다.
type Player = {
name: string,
age?:number
}
function playerMaker1(name:string) : Player {
return {
name
}
}
const playerMaker2 = (name:string) : Player => ({name})
const nico = playerMaker1("nico")
nico.age = 12
type Player = {
readonly name:Name
age?:Age
}
const play: [string, number, boolean] = ["nico", 1, true];
Call Signatures는 다음과 같이 함수의 매개 변수(parameter)와 반환 타입을 지정합니다.
함수의 call signature type 만들기
type Add = (a:number, b:number) => number;
const add:Add = (a, b) => a + b;
Function Overloading은 직접 작성하기보다 외부 라이브러리에 자주 보이는 형태로, 하나의 함수가 복수의 Call Signature를 가질 때 발생한다
type Add = {
(a: number, b: number): number,
(a: number, b: string): number
}
const add: Add = (a, b) => {
if (typeof b === "string") return a;
return a + b;
}
type Add2 = {
(a: number, b: number): number,
(a: number, b: number, c: number): number
}
const add2: Add2 = (a, b, c?: number) => {
if (c) return a + b + c;
return a + b;
}
예를 들어, Next.js의 라우터 push가 대충 두 가지 방법으로 페이지를 이동한다고 할 때, 패키지나 라이브러리는 아래와 같이 두 가지 경우의 Overloading으로 디자인되어 있을 것이다
type Config = {
path: string,
state: number
}
type Push = {
(config: Config): void,
(config: string): void
}
const push: Push = (config) => {
if (typeof config === "string") console.log(config);
else console.log(config.path);
}
ts에서 다형성(polymorphism)을 주는 방법 -> generic
generic은 쉽게 말해 type의 placeholder이다. 인자들과 반환값에 대하여 형태(타입)에 따라 그에 상응하는 형태(타입)를 갖을 수 있다. any와의 차이점은 해당 타입에 대한 정보를 잃지 않는다. any는 any로서 밖에 알 수 없지만 generics는 타입 정보를 알 수 있다.
type에 generic을 적용한 뒤 맨 아래 함수 실해부들을 확인해보면 타입스크립트가 자체적으로 타입을 만들어주고 있는것을 볼 수 있다.
type SuperPrint = {
<T>(arr: T[]):void
// call signature에서 genric 받기
}
const superPrint: SuperPrint = (arr) => {
arr.forEach(i => console.log(i))
}
superPrint([1,2,3,4])
superPrint([true,false,true])
superPrint([1,2,true,false])
제네릭은 단일 타입이 아닌 다양한 타입에서 작동할 수 있는 컴포넌트를 생성하기 위해 만들어진 구문이다.
제네릭은 선언 시점이 아니라 생성 시점에 타입을 명시하여 하나의 타입만이 아닌 다양한 타입을 사용할 수 있도록 하는 기법이다.
타입스크립트에서 제네릭을 통해 인터페이스, 함수 등의 재사용성을 높일 수 있다.
(Generic은 Call Signature를 원시타입으로 하나씩 추가하는 형태라고 할 수 있다.)
function identity< Type >(arg: Type): Type {
return arg;
}
// 제네릭 화살표 함수 (tsx기준)
const identity=< Type extends {} >(arg: Type):Type => {
return arg;
}
let output = identity< string >("myString"); // 첫 번째 방법
let output = identity("myString"); // 두 번째 방법
// 두 번째 방법은 type argument inference(타입 인수 유추)를 사용합니다. 즉, 컴파일러가 전달하는 인수 유형에 따라 자동으로 Type 값을 설정하기를 원합니다.