打字稿:使用泛型正确打字

时间:2020-03-13 22:23:04

标签: typescript es6-promise typescript-typings

我最近从JavaScript切换到TypeScript,感觉真的很棒。在做我的日常工作时,我想知道Promises是如何工作的,在经过简短的Google搜索之后,我发现了这篇可爱的文章:https://softchris.github.io/pages/javascript-promises.html#why。然后,我认为将其转换为TypeScript是一个好习惯。好了,正如您在下面看到的那样,它可以正常工作。我无法解决的一件事是dataonSuccessonFailure仍然具有any而不是then<R>(){}中的泛型。 errorany的事实是故意的。

那么有人可以帮我解决这个问题吗?要使用该代码,您可以使用https://stackblitz.com/edit/swear-ts

非常感谢! :)

type Resolver<T> = (x: T) => void;
type Rejecter = (x: any) => void;

type Factory<T> = (resolve: Resolver<T>, reject?: Rejecter) => void;

type OnSuccessFn<T, R> = (data: T) => R;
type OnFailureFn<R> = (error: any) => R;

class Swear<T = any> {
  private data: any;

  private resolveWasInvoked = false;
  private errorWasHandled = false;

  private onSuccess: OnSuccessFn<T, any>;
  private onFailure?: OnFailureFn<any>;

  constructor(
    private factory: Factory<T>,
    private error: null | Error = null
  ) { }

  private resolve(data: T): void {
    if (!this.error) {
      const result = this.onSuccess(data);

      if (result) {
        this.data = result;
      }

      this.resolveWasInvoked = true;
    }
  }

  private reject(error: any): void {
    if (!this.resolveWasInvoked) {
      this.error = error;

      if (this.onFailure) {
        const result = this.onFailure(error);

        if (result) {
          this.data = result;
        }

        this.errorWasHandled = true;
      }
    }
  }

  public then<R>(
    OnSuccessFn: OnSuccessFn<T, R>,
    OnFailureFn?: OnFailureFn<R>
  ): Swear<R> {
    this.onSuccess = OnSuccessFn;
    this.onFailure = OnFailureFn;

    this.factory(
      (data: T): void => this.resolve(data),
      (error: any): void => this.reject(error),
    )

    return new Swear<R>((resolve) => {
      resolve(<R>this.data);
    }, !this.errorWasHandled ? this.error : null);
  }

  catch(catchFn: (error: any) => void): void {
    if (!this.errorWasHandled && this.error) {
      catchFn(this.error);
    }
  }
}

const swear: Swear<string> = new Swear((resolve, reject) => {
  resolve('Hello');
  // reject('Ups..');
})

swear
  .then(data => data + ' World!')
  // .then(data => data.length)
  .then(data => console.info(data))
  .catch(error => console.error(`Catched: ${error}`));

1 个答案:

答案 0 :(得分:0)

做了一些基本的重构来摆脱 any 类型。由于您的函数onSuccess具有两种通用类型,一种用于输入,一种则返回。我向您的班级添加了相同的泛型,以删除大多数 any 用法。此外,错误的打字稿中带有错误类型,您无需使用任何类型。

    type Resolver<T> = (x: T) => void;
    type Rejecter = (x) => void;

    type Factory<T> = (resolve: Resolver<T>, reject?: Rejecter) => void;

    type OnSuccessFn<T, R> = (data: T) => R;
    type OnFailureFn<R> = (error: Error) => R;

    class Swear<T, R> {
     private data: R;
     private resolveWasInvoked = false;
     private errorWasHandled = false;

     private onSuccess: OnSuccessFn<T, R>;
     private onFailure?: OnFailureFn<R>;

     constructor(
       private factory: Factory<T>,
       private error: null | Error = null
     ) { }

     private resolve(data: T): void {
     if (!this.error) {
         const result = this.onSuccess(data);

        if (result) {
          this.data = result;
        }
        this.resolveWasInvoked = true;
      }
    }

   private reject(error: Error): void {
   if (!this.resolveWasInvoked) {
       this.error = error;

       if (this.onFailure) {
          const result = this.onFailure(error);

       if (result) {
          this.data = result;
      }
      this.errorWasHandled = true;
    }
  }
}

 public then(
    OnSuccessFn: OnSuccessFn<T, R>,
    OnFailureFn?: OnFailureFn<R>
   ) {
       this.onSuccess = OnSuccessFn;
       this.onFailure = OnFailureFn;

       this.factory(
       (data: T): void => this.resolve(data),
       (error: Error): void => this.reject(error),
      )

       return new Swear<any, R>((resolve) => {
       resolve(<R>this.data);
     }, !this.errorWasHandled ? this.error : null);
  }

  catch(catchFn: (error: Error) => void): void {
    if (!this.errorWasHandled && this.error) {
      catchFn(this.error);
    }
  }
}
const swear: Swear<string, void> = new Swear((resolve, reject) => {
    resolve('Hello');
    // reject('Ups..');
 })

swear
  .then(data => data + ' World!')
  .then(data => console.log(data))
  .catch(error => console.error(`Catched: ${error}`));code here