새로운 디바운스 기능을 위한 폴란드어 유형

13255 단어 tutorialtypescript
항상 개선의 여지가 있으므로 이전 기사에서 만든 디바운스 기능에서 무엇을 개선할 수 있는지 살펴보겠습니다.

// debounce.function.ts

export function debounce<A = unknown, R = void>(
  fn: (args: A) => R,
  ms: number
): [(args: A) => Promise<R>, () => void] {
  let timer: NodeJS.Timeout;

  const debouncedFunc = (args: A): Promise<R> =>
      new Promise((resolve) => {
          if (timer) {
              clearTimeout(timer);
          }

          timer = setTimeout(() => {
              resolve(fn(args));
          }, ms);
      });

  const teardown = () => clearTimeout(timer);

  return [debouncedFunc, teardown];
}


작동하지만 투박해 보입니다.

Nodejs에 연결된
  • 타이머 유형;
  • 은 여러 기본 인수, 즉 두 개의 숫자를 허용하지 않습니다.
  • 반환 형식을 읽기 어렵습니다.

  • 가장 쉬운 타이머 유형부터 시작하겠습니다. NodeJS.Timeout 을 사용하여 입력하는 대신 ReturnType 을 사용하여 보다 교활한 방식으로 입력할 수 있습니다.

    let timer: ReturnType<typeof setTimeout>;
    


    따라서 타이머는 setTimeout이 반환하는 모든 것입니다.

    이제 아마도 가장 흥미로운 부분일 것입니다. 디바운스 함수에 단일 유형의 개체 대신 모든 유형의 인수를 얼마든지 전달할 수 있습니다.

    먼저 거기에 도달하려면 typescript의 모든 함수에 적용 가능한 인터페이스를 이해해야 합니다. 이름을 지정하고 FunctionWithArguments이라고 하면 다음과 같이 표시됩니다.

    // ./models/function-with-arguments.model.ts
    
    export interface FunctionWithArguments {
      (...args: any): any;
    }
    


    이 단일 인터페이스를 사용하면 debounce<A = unknown, R = void> 에 인수 유형과 반환 유형을 별도로 입력할 필요가 없습니다. 인수 + 반환 유형 대신 함수를 기대하는 유형으로 바로 이동할 수 있습니다. debounce<F extends FunctionWithArguments>(fn: F, ms: number) .

    그래서 우리는 F 의 확장인 FunctionWithArguments 함수를 얻습니다. 그러면 디바운스 함수 인터페이스는 어떻게 생겼을까요? 앞서 언급한 함수를 사용하고 유형 ParametersReturnType 제네릭을 활용하여 모든 인수의 압축을 풀고 F 함수가 전달하는 유형을 반환합니다.

    // ./models/debounced-function.model.ts
    
    import { FunctionWithArguments } from './function-with-arguments.model';
    
    export interface DebouncedFunction<F extends FunctionWithArguments> {
      (...args: Parameters<F>): Promise<ReturnType<F>>;
    }
    


    보시다시피 DebouncedFunction은 모든 함수를 허용하고 인수와 반환 유형을 명시적으로 전달할 필요 없이 비동기 버전인 함수를 생성합니다.

    처음 두 가지 사항을 처리했으므로 이제 반환 유형 debounce을 좀 더 읽기 쉽게 만들 차례입니다.
    [(args: A) => Promise<R>, () => void] 은 기본적으로 Array<DebouncedFunction<F> | (() => void)> 과 동일하므로 별도의 인터페이스를 생성하여 엄격하게 입력할 수 있습니다.

    // ./models/debounce-return.model.ts
    import { DebouncedFunction } from './debounced-function.model';
    import { FunctionWithArguments } from './function-with-arguments.model';
    
    export interface DebounceReturn<F extends FunctionWithArguments> extends Array<DebouncedFunction<F> | (() => void)> {
      0: (...args: Parameters<F>) => Promise<ReturnType<F>>;
      1: () => void;
    }
    


    엄격한 형식의 튜플입니다.

    이 모든 것을 합치면 우리는 더 이상 명시적으로 인수와 반환 유형을 전달할 필요가 없지만 대신 전달된 함수에서 추론하는 더 나은 형식의 디바운스 함수를 얻습니다.

    // debounce.function.ts
    import { DebouncedFunction, DebounceReturn, FunctionWithArguments } from './models';
    
    export function debounce<F extends FunctionWithArguments>(fn: F, ms: number): DebounceReturn<F> {
      let timer: ReturnType<typeof setTimeout>;
    
      const debouncedFunc: DebouncedFunction<F> = (...args) =>
        new Promise((resolve) => {
          if (timer) {
            clearTimeout(timer);
          }
    
          timer = setTimeout(() => {
            resolve(fn(...args as unknown[]));
          }, ms);
        });
    
      const teardown = () => {
        clearTimeout(timer);
      };
    
      return [debouncedFunc, teardown];
    }
    


    라이브로 해보세요 here .

    저장소는 here 입니다.

    npm 패키지 here 으로 포장됩니다.

    좋은 웹페이지 즐겨찾기