노마드코더 타입스크립트 챌린지

지인·2023년 2월 6일
0

TIL

목록 보기
10/17
post-thumbnail

2.1

  • 명시적으로 타입을 써주는 것 보다는 TS가 스스로 타입을 추론하는 것이 좋다.
let a = "hello"; //이게 더 좋다.
let b :boolean = true;

let c : number[] = [];
// 단, TS가 타입을 추론하지 못할 때는 명시적으로 써주는 것도 유용하다. 

2.2

  • optional
const playerNico : {
    name: string,
    age?:number
} = {
  name: "nico"
}

위 코드는 다음과 같이 바꿔볼 수 도 있다.

type Player : {
  name: string,
  age?: number
}
  
const playNico :Player = {
	name:"nico"
}
  • optional narrowing
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

2.3

  • readonly을 TS를 통해 추가할 수 있다. (재할당 할 수 없다.)
type Player = {
	readonly name:Name
    age?:Age
}
  • Tuple은 정해진 개수와 순서에 따라 배열을 선언하는 것을 말한다.
const play: [string, number, boolean] = ["nico", 1, true];
  • undefined, null, any
    - any: 아무 타입 (사용을 지양하자)
    - undefined: 선언X 할당X
    - null: 선언O 할당X

2.4

  • void, unknown, never
    - void : 값을 반환하지 않는 함수의 반환 값이다.
    • unknown : any와 비슷하나 any보다는 더 안전하다. (사용을 지양하자)
    • never : 함수의 리턴 값이 절대 실행되지 않는 값을 의미한다. (함수가 예외를 throw하거나 프로그램 실행을 종료함을 의미한다.)

3.0

Call Signatures는 다음과 같이 함수의 매개 변수(parameter)와 반환 타입을 지정합니다.

함수의 call signature type 만들기

type Add = (a:number, b:number) => number;
const add:Add = (a, b) => a + b;

3.1

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);
}

3.2

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])

3.3

제네릭은 단일 타입이 아닌 다양한 타입에서 작동할 수 있는 컴포넌트를 생성하기 위해 만들어진 구문이다.
제네릭은 선언 시점이 아니라 생성 시점에 타입을 명시하여 하나의 타입만이 아닌 다양한 타입을 사용할 수 있도록 하는 기법이다.

타입스크립트에서 제네릭을 통해 인터페이스, 함수 등의 재사용성을 높일 수 있다.
(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 값을 설정하기를 원합니다.
profile
안녕하세요

0개의 댓글