How do I type a decorated property which type is changed by the decorator?
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty{ height:90px;width:728px;box-sizing:border-box;
}
Here's some code that works perfectly in 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 is an alternative to promises that allows cancelling and managing them similar to Observable from RxJS. Since JS promises don't allow cancelling, Ember Concurrency uses yield
instead of async
/await
.
The task
decorator used above converts a generator function into a TaskProperty
instance that has a .perform()
method.
Please note, that, though weird, this pattern has proven its handiness and reliability in non-typed JS apps.
But typing it presents a challenge.
Here are
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;
}
These types aren't official and can be customized.
I struggle with properly typing the topmost code sample.
The error I'm getting is:
Property
perform
does not exist on type() => IterableIterator<any>
.
It is understandable, since fetchRecord
is defined as a generator.
Moreover, TypeScript officially does not support decorators that change the type of decorated property.
So the question is: how to work around the limitation and type such a decorator without reverting to @ts-ignore
?
In addition to typing the fetchRecord
property, I would like to properly type the arguments that I pass into this.fetchRecord.perform()
and which are received by the generator.
Thank you. ^__^
typescript ember.js decorator typescript-decorator ember-concurrency
add a comment |
Here's some code that works perfectly in 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 is an alternative to promises that allows cancelling and managing them similar to Observable from RxJS. Since JS promises don't allow cancelling, Ember Concurrency uses yield
instead of async
/await
.
The task
decorator used above converts a generator function into a TaskProperty
instance that has a .perform()
method.
Please note, that, though weird, this pattern has proven its handiness and reliability in non-typed JS apps.
But typing it presents a challenge.
Here are
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;
}
These types aren't official and can be customized.
I struggle with properly typing the topmost code sample.
The error I'm getting is:
Property
perform
does not exist on type() => IterableIterator<any>
.
It is understandable, since fetchRecord
is defined as a generator.
Moreover, TypeScript officially does not support decorators that change the type of decorated property.
So the question is: how to work around the limitation and type such a decorator without reverting to @ts-ignore
?
In addition to typing the fetchRecord
property, I would like to properly type the arguments that I pass into this.fetchRecord.perform()
and which are received by the generator.
Thank you. ^__^
typescript ember.js decorator typescript-decorator ember-concurrency
Please don't put tags in question titles "You should not force a tag into your title."
– Liam
Jan 3 at 10:57
Shouldn't the returngeneratorFn
return an iteration of promises ?
– Titian Cernicova-Dragomir
Jan 3 at 11:04
add a comment |
Here's some code that works perfectly in 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 is an alternative to promises that allows cancelling and managing them similar to Observable from RxJS. Since JS promises don't allow cancelling, Ember Concurrency uses yield
instead of async
/await
.
The task
decorator used above converts a generator function into a TaskProperty
instance that has a .perform()
method.
Please note, that, though weird, this pattern has proven its handiness and reliability in non-typed JS apps.
But typing it presents a challenge.
Here are
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;
}
These types aren't official and can be customized.
I struggle with properly typing the topmost code sample.
The error I'm getting is:
Property
perform
does not exist on type() => IterableIterator<any>
.
It is understandable, since fetchRecord
is defined as a generator.
Moreover, TypeScript officially does not support decorators that change the type of decorated property.
So the question is: how to work around the limitation and type such a decorator without reverting to @ts-ignore
?
In addition to typing the fetchRecord
property, I would like to properly type the arguments that I pass into this.fetchRecord.perform()
and which are received by the generator.
Thank you. ^__^
typescript ember.js decorator typescript-decorator ember-concurrency
Here's some code that works perfectly in 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 is an alternative to promises that allows cancelling and managing them similar to Observable from RxJS. Since JS promises don't allow cancelling, Ember Concurrency uses yield
instead of async
/await
.
The task
decorator used above converts a generator function into a TaskProperty
instance that has a .perform()
method.
Please note, that, though weird, this pattern has proven its handiness and reliability in non-typed JS apps.
But typing it presents a challenge.
Here are
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;
}
These types aren't official and can be customized.
I struggle with properly typing the topmost code sample.
The error I'm getting is:
Property
perform
does not exist on type() => IterableIterator<any>
.
It is understandable, since fetchRecord
is defined as a generator.
Moreover, TypeScript officially does not support decorators that change the type of decorated property.
So the question is: how to work around the limitation and type such a decorator without reverting to @ts-ignore
?
In addition to typing the fetchRecord
property, I would like to properly type the arguments that I pass into this.fetchRecord.perform()
and which are received by the generator.
Thank you. ^__^
typescript ember.js decorator typescript-decorator ember-concurrency
typescript ember.js decorator typescript-decorator ember-concurrency
edited Jan 3 at 10:57


Liam
16.5k1678131
16.5k1678131
asked Jan 3 at 10:47
Andrey Mikhaylov - lolmausAndrey Mikhaylov - lolmaus
18k456104
18k456104
Please don't put tags in question titles "You should not force a tag into your title."
– Liam
Jan 3 at 10:57
Shouldn't the returngeneratorFn
return an iteration of promises ?
– Titian Cernicova-Dragomir
Jan 3 at 11:04
add a comment |
Please don't put tags in question titles "You should not force a tag into your title."
– Liam
Jan 3 at 10:57
Shouldn't the returngeneratorFn
return an iteration of promises ?
– Titian Cernicova-Dragomir
Jan 3 at 11:04
Please don't put tags in question titles "You should not force a tag into your title."
– Liam
Jan 3 at 10:57
Please don't put tags in question titles "You should not force a tag into your title."
– Liam
Jan 3 at 10:57
Shouldn't the return
generatorFn
return an iteration of promises ?– Titian Cernicova-Dragomir
Jan 3 at 11:04
Shouldn't the return
generatorFn
return an iteration of promises ?– Titian Cernicova-Dragomir
Jan 3 at 11:04
add a comment |
0
active
oldest
votes
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54020783%2fhow-do-i-type-a-decorated-property-which-type-is-changed-by-the-decorator%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
0
active
oldest
votes
0
active
oldest
votes
active
oldest
votes
active
oldest
votes
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54020783%2fhow-do-i-type-a-decorated-property-which-type-is-changed-by-the-decorator%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Please don't put tags in question titles "You should not force a tag into your title."
– Liam
Jan 3 at 10:57
Shouldn't the return
generatorFn
return an iteration of promises ?– Titian Cernicova-Dragomir
Jan 3 at 11:04