如何键入由装饰器更改的装饰属性?

时间:2019-01-03 10:47:04

标签: typescript ember.js decorator typescript-decorator ember-concurrency

以下是在JS中完美运行的代码:

import Component from '@ember/component';
import {task} from 'ember-concurrency';

class Foo extends Component {
  currentRecordId!: string; // passed from template

  @task
  fetchRecord *(id) {
    return yield this.store.findRecord('foo', id);
  }

  async fetchCurrentRecord() {
    return this.fetchRecord.perform(this.currentRecordId);
  }
}

Ember并发是Promise的替代方法,它允许取消和管理Promise,类似于RxJS中的Observable。由于JS许诺不允许取消,因此Ember Concurrency使用yield而不是async / await

上面使用的task装饰器将生成器函数转换为具有TaskProperty方法的.perform()实例。

请注意,尽管很奇怪,但这种模式已在非类型化JS应用程序中证明了其方便性和可靠性。

但是输入它会带来挑战。


这是

export declare function task<T, A>(generatorFn: () => Iterator<T>): Task<T, () => TaskInstance<T>>;

export declare function task<T, A>(
  generatorFn: (a: A) => Iterator<T>
): Task<T, (a: A) => TaskInstance<T>>;

export declare function task<T, A>(
  generatorFn: (a: A) => Iterator<PromiseLike<T>>
): Task<T, (a: A) => TaskInstance<T>>;

export declare function task<T, A1, A2>(
  generatorFn: (a1: A1, a2: A2) => Iterator<T>
): Task<T, (a1: A1, a2: A2) => TaskInstance<T>>;

// More variants of arguments skipped

export interface TaskInstance<T> extends PromiseLike<T> {
  readonly error?: any;
  readonly hasStarted: ComputedProperty<boolean>;
  readonly isCanceled: ComputedProperty<boolean>;
  readonly isDropped: ComputedProperty<boolean>;
  readonly isError: boolean;
  readonly isFinished: ComputedProperty<boolean>;
  readonly isRunning: ComputedProperty<boolean>;
  readonly isSuccessful: boolean;
  readonly state: ComputedProperty<TaskInstanceState>;
  readonly value?: T;
  cancel(): void;
  catch(): RSVP.Promise<any>;
  finally(): RSVP.Promise<any>;
  then<TResult1 = T, TResult2 = never>(
    onfulfilled?: ((value: T) => TResult1 | RSVP.Promise<TResult1>) | undefined | null,
    onrejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | undefined | null
  ): RSVP.Promise<TResult1 | TResult2>;
}

interface Task<T> extends TaskProperty<T> {
    readonly isIdle: boolean;
    readonly isQueued: boolean;
    readonly isRunning: boolean;
    readonly last?: TaskInstance<T>;
    readonly lastCanceled?: TaskInstance<T>;
    readonly lastComplete?: TaskInstance<T>;
    readonly lastErrored?: TaskInstance<T>;
    readonly lastIncomplete?: TaskInstance<T>;
    readonly lastPerformed?: TaskInstance<T>;
    readonly lastRunning?: TaskInstance<T>;
    readonly lastSuccessful?: TaskInstance<T>;
    readonly performCount: number;
    readonly state: TaskState;
    perform(...args: any[]): TaskInstance<T>;
    cancelAll(): void;
}

export interface TaskProperty<T> extends ComputedProperty<T> {
    cancelOn(eventNames: string[]): this;
    debug(): this;
    drop(): this;
    enqueue(): this;
    group(groupPath: string): this;
    keepLatest(): this;
    maxConcurrency(n: number): this;
    on(eventNames: string[]): this;
    restartable(): this;
}

这些类型不是官方的,可以自定义。


我很难正确输入最上面的代码示例。

我得到的错误是:

  

属性perform在类型() => IterableIterator<any>上不存在。

这是可以理解的,因为fetchRecord被定义为生成器。

此外,TypeScript officially does not support装饰器会更改装饰属性的类型。

所以问题是:如何解决限制并键入这样的修饰符而不返回到@ts-ignore

除了键入fetchRecord属性之外,我还要正确键入传递给this.fetchRecord.perform()并由生成器接收的参数。

谢谢。 ^ __ ^

0 个答案:

没有答案