From eb51235a5f014a8e8c5acfa3a46a72c167a416f7 Mon Sep 17 00:00:00 2001 From: Justin Fagnani Date: Mon, 10 Jul 2023 13:11:46 -0700 Subject: [PATCH 1/3] Infer the return type of Task.render() --- .changeset/spicy-mugs-eat.md | 5 +++++ packages/labs/task/src/task.ts | 20 +++++++++++++------- packages/labs/task/src/test/task_test.ts | 15 +++++++++++++++ 3 files changed, 33 insertions(+), 7 deletions(-) create mode 100644 .changeset/spicy-mugs-eat.md diff --git a/.changeset/spicy-mugs-eat.md b/.changeset/spicy-mugs-eat.md new file mode 100644 index 0000000000..7a05b06ceb --- /dev/null +++ b/.changeset/spicy-mugs-eat.md @@ -0,0 +1,5 @@ +--- +'@lit-labs/task': patch +--- + +Infer the return type of Task.render() diff --git a/packages/labs/task/src/task.ts b/packages/labs/task/src/task.ts index 5e7f6f4322..7e1a09b6c2 100644 --- a/packages/labs/task/src/task.ts +++ b/packages/labs/task/src/task.ts @@ -327,19 +327,20 @@ export class Task< return this._error; } - render(renderer: StatusRenderer) { + render>(renderer: T) { switch (this.status) { case TaskStatus.INITIAL: - return renderer.initial?.(); + return renderer.initial?.() as MaybeReturnType; case TaskStatus.PENDING: - return renderer.pending?.(); + return renderer.pending?.() as MaybeReturnType; case TaskStatus.COMPLETE: - return renderer.complete?.(this.value!); + return renderer.complete?.(this.value!) as MaybeReturnType< + T['complete'] + >; case TaskStatus.ERROR: - return renderer.error?.(this.error); + return renderer.error?.(this.error) as MaybeReturnType; default: - // exhaustiveness check - this.status as void; + throw new Error(`Unexpected status: ${this.status}`); } } @@ -351,3 +352,8 @@ export class Task< : args !== prev; } } + +/* eslint-disable @typescript-eslint/no-explicit-any */ +type MaybeReturnType any)> = + T extends (...args: any) => any ? ReturnType : undefined; +/* eslint-enable @typescript-eslint/no-explicit-any */ diff --git a/packages/labs/task/src/test/task_test.ts b/packages/labs/task/src/test/task_test.ts index bce98225a6..8ebecad085 100644 --- a/packages/labs/task/src/test/task_test.ts +++ b/packages/labs/task/src/test/task_test.ts @@ -942,4 +942,19 @@ suite('Task', () => { assert.equal(el.task.value, secondValue); assert.notEqual(firstValue, secondValue); }); + + test('type-only render return type test', () => { + class TestElement extends ReactiveElement { + task = new Task(this, () => 'abc'); + } + customElements.define(generateElementName(), TestElement); + const el = new TestElement(); + + const acceptNumberOrUndefined = (x?: number) => x; + + acceptNumberOrUndefined(el.task.render({initial: () => 123})); + acceptNumberOrUndefined(el.task.render({complete: () => 123})); + acceptNumberOrUndefined(el.task.render({pending: () => 123})); + acceptNumberOrUndefined(el.task.render({error: () => 123})); + }); }); From 4fd43d2625423b839cde05d0121b16e94172c3ad Mon Sep 17 00:00:00 2001 From: Justin Fagnani Date: Mon, 10 Jul 2023 17:08:36 -0700 Subject: [PATCH 2/3] Address feedback --- packages/labs/task/src/task.ts | 7 +++---- packages/labs/task/src/test/task_test.ts | 24 ++++++++++++++++++------ 2 files changed, 21 insertions(+), 10 deletions(-) diff --git a/packages/labs/task/src/task.ts b/packages/labs/task/src/task.ts index 7e1a09b6c2..5ca65d2cf7 100644 --- a/packages/labs/task/src/task.ts +++ b/packages/labs/task/src/task.ts @@ -353,7 +353,6 @@ export class Task< } } -/* eslint-disable @typescript-eslint/no-explicit-any */ -type MaybeReturnType any)> = - T extends (...args: any) => any ? ReturnType : undefined; -/* eslint-enable @typescript-eslint/no-explicit-any */ +type MaybeReturnType = F extends (...args: unknown[]) => infer R + ? R + : undefined; diff --git a/packages/labs/task/src/test/task_test.ts b/packages/labs/task/src/test/task_test.ts index 8ebecad085..ff252ebacf 100644 --- a/packages/labs/task/src/test/task_test.ts +++ b/packages/labs/task/src/test/task_test.ts @@ -950,11 +950,23 @@ suite('Task', () => { customElements.define(generateElementName(), TestElement); const el = new TestElement(); - const acceptNumberOrUndefined = (x?: number) => x; - - acceptNumberOrUndefined(el.task.render({initial: () => 123})); - acceptNumberOrUndefined(el.task.render({complete: () => 123})); - acceptNumberOrUndefined(el.task.render({pending: () => 123})); - acceptNumberOrUndefined(el.task.render({error: () => 123})); + const accept = (x: T) => x; + + accept(el.task.render({initial: () => 123})); + accept(el.task.render({complete: () => 123})); + accept(el.task.render({pending: () => 123})); + accept(el.task.render({error: () => 123})); + accept( + el.task.render({initial: () => 123, complete: () => 123}) + ); + + accept( + el.task.render({ + initial: () => 123, + complete: () => 123, + pending: () => 123, + error: () => 123, + }) + ); }); }); From 348ac839b8b43e346eb2d055f0e483170a483b6c Mon Sep 17 00:00:00 2001 From: Justin Fagnani Date: Mon, 10 Jul 2023 17:12:35 -0700 Subject: [PATCH 3/3] Default task return type to unknown --- packages/labs/task/src/task.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/labs/task/src/task.ts b/packages/labs/task/src/task.ts index 5ca65d2cf7..7e24427280 100644 --- a/packages/labs/task/src/task.ts +++ b/packages/labs/task/src/task.ts @@ -10,8 +10,7 @@ export interface TaskFunctionOptions { signal?: AbortSignal; } -// eslint-disable-next-line @typescript-eslint/no-explicit-any -export type TaskFunction, R = any> = ( +export type TaskFunction, R = unknown> = ( args: D, options?: TaskFunctionOptions ) => R | typeof initialState | Promise;