타입스크립트 교과서 3.5~3.11 정리

이수빈·2023년 10월 5일
0

Typescript

목록 보기
7/17
post-thumbnail

forEach type 만들어보기

  • 먼저 기존의 Array 인터페이스를 선언병합 하는 과정이 필요하다.
  • 선언병합 이후 테스트 케이스를 추가해가면서 매개변수를 수정한다. (실제 구현은 하지 않았기 때문에 실행되지는 않는다.)
  • value type을 제네릭으로 받아야 value에 상관없이 적용가능함.

interface Array<T>{
    myForEach(callback:(v:T, i:number, a:T[])=>void):void;
}
  
const array = [1,2,3];
[1,2,3].myForEach((v)=> {})
  

map type 만들어보기

  interface Array<T>{
    myForEach(callback:(v:T, i:number, a:T[])=>void):void;
    myMap<U>(callback:(value :T, index:number , array: T[]) => U): U[];
}
  • callback fn의 value는 array의 원소 type인 T이여야 함.
  • return type은 기존의 원소 type과 다를 수 있으므로 제너릭을 사용

filter type 만들기

  • string|number[]에서 string만 filter할 경우 return type이 달라지는 현상 발생
  • 새로운 제너릭 도입 단, 배열요소의 타입을 벗어 날 순 없음. ("S extends T")
  • 타입서술 함수를 통해 타입을 직접적으로 좁혀주는 방식을 사용함, 타입서술함수는 boolean을 반환해야함.
  interface Array<T>{
    myForEach(callback:(v:T, i:number, a:T[])=>void):void;
    myMap<U>(callback:(value :T, index:number , array: T[]) => U): U[];
    myFilter<S extends T>(callback : (v:T, i: number , a : T[]) => v is S, thisArg? : any): S[];
    myFilter(callback : (v:T, i: number , a : T[]) => boolean, thisArg? : any): T[];

}

reduce type 만들기

  • 3가지케이스, 초기값이 없는경우, 초기값이 있는데 array T와 타입이 동일한 경우, 초기값이 있는데 array T와 타입이 다른경우 존재
  myReduce(callback : (previousValue : T, currentValue : T, currentIndex :number, array: T[]) => T):T;
  myReduce(callback : (previousValue : T, currentValue : T, currentIndex :number, array: T[]) => T , initalValue : T):T;
  myReduce<U>(callback : (previousValue : T, currentValue : T, currentIndex :number, array: T[]) => U ,initalValue : U): U;

flat type 분석하기

  • flat 메서드의 매기변수 => A,D 를 제너릭으로 받음 A는 원본배열, d는 매개변수인 낮출 차원수임

  • FlatArray는 컨디셔널 타입을 인덱스 접근타입으로 나타냄 => depth가 -1이라면 done이라서 Arr type을 반환하고 아니라면 recur type을 반환

  • recur 타입은 다시 컨디셔널 타입을 실행

  • Arr extends ReadlonlyArray 라면? 의 의미

  • 모든 배열은 ReadonlyArray를 extend 할 수 있으므로, 참임 (readonly T[]) 와 같은 경우임.(배열인지 아닌지 check하는 조건)

  • 뒤에 배열은 depth를 1줄이고 다시 줄인 depth를 바탕으로 FlatArray를 호출하는 역할임

  • detph가 -1일경우 done 상태가되면서 Arr를 반환, 아니면 InnerArr를 계속해서 전달함.

  • infer가 추론되는 방법?

  • ReadOnlyArray 는 readonly T[]와 동일함. => 이러면 괄호를 하나 벗길 수 있도록 쉽게 추론가능

  • 아니면 ReadOnlyArray에서 내부구현사항에 return값이 []가 붙혀서 반환되는걸로 추론?

type FlatArray<Arr, Depth extends number> = {
    "done": Arr,
    "recur": Arr extends ReadonlyArray<infer InnerArr>
        ? FlatArray<InnerArr, [-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20][Depth]>
        : Arr
}[Depth extends -1 ? "done" : "recur"]; // 컨디셔녈 타입을 인덱스 접근타입으로 나타냄
  
  
interface Array<T> {

   
    flatMap<U, This = undefined> (
        callback: (this: This, value: T, index: number, array: T[]) => U | ReadonlyArray<U>,
        thisArg?: This
    ): U[]

   
    flat<A, D extends number = 1>(
        this: A,
        depth?: D
    ): FlatArray<A, D>[] // flat 메소드, FlatArray 를 반환함.
}

interface ReadonlyArray<T> {

    flatMap<U, This = undefined> (
        callback: (this: This, value: T, index: number, array: T[]) => U | ReadonlyArray<U>,
        thisArg?: This
    ): U[]


    flat<A, D extends number = 1>(
        this: A,
        depth?: D
    ): FlatArray<A, D>[]
  }

infer 키워드

  • 컨디셔널 타입과 함께 사용되어야 함. 추론을 맡기고 싶은 부분에 infer 키워드와 타입변수를 넣음.

Promise, awaited type분석

  • Promise Constructor 가 Promise type의 구현체임.
interface PromiseConstructor {
   
    readonly prototype: Promise<any>;

    new <T>(executor: (resolve: (value: T | PromiseLike<T>) => void, reject: (reason?: any) => void) => void): Promise<T>;
   
    all<T extends readonly unknown[] | []>(values: T): Promise<{ -readonly [P in keyof T]: Awaited<T[P]> }>;

    race<T extends readonly unknown[] | []>(values: T): Promise<Awaited<T[number]>>;
  
    reject<T = never>(reason?: any): Promise<T>;

    resolve<T>(value: T): Promise<Awaited<T>>;
    
    resolve<T>(value: T | PromiseLike<T>): Promise<Awaited<T>>;
}

declare var Promise: PromiseConstructor;
  

Awaited Type

  • await 키워드가 붙으면 TS에서 타입이 Awaited 제너릭 타입을 감싸짐.

  • 컨디셔널 타입의 3번 중첩

  • 첫번째 조건 null, undefined check => Awaited = null, Awaited = undefined임

  • 두번째 조건 object여부 check, primitive type일경우 Awaited = string, Awaited = number임

  • T가 객체인경우에도 then이라는 메소드를 가지고 있어야함.(&조건)

  • 3번째 조건 infer를 두번하는 이유 => chaining 때문에(형태를 맞춰서 추론..)

  • T가 프로미스 객체일일때 => Awaited 는 Awaited가 됨. T는 Promise이고, V는 X임. (infer 키워드를 통해 추론함)

  • 따라서 Awaited<Promise>는 Awaited가 됨.

  • Awaited<Promise> = Awaited

type Awaited<T> =
    T extends null | undefined ? T : // special case for `null | undefined` when not in `--strictNullChecks` mode
        T extends object & { then(onfulfilled: infer F, ...args: infer _): any } ? // `await` only unwraps object types with a callable `then`. Non-object types are not unwrapped
            F extends ((value: infer V, ...args: infer _) => any) ? // if the argument to `then` is callable, extracts the first argument
                Awaited<V> : // recursively unwrap the value
                never : // the argument to `then` was not callable
        T; // non-object or non-thenable
profile
응애 나 애기 개발자

0개의 댓글