1

下面是一些在 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 Concurrency 是 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官方不支持改变装饰属性类型的装饰器。

所以问题是:如何绕过限制并键入这样的装饰器而不恢复到@ts-ignore

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

谢谢你。^__^

4

0 回答 0