Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use same types for return and arg #501

Open
Techn1x opened this issue Nov 10, 2022 · 2 comments
Open

Use same types for return and arg #501

Techn1x opened this issue Nov 10, 2022 · 2 comments

Comments

@Techn1x
Copy link

Techn1x commented Nov 10, 2022

I'm trying to build a typed task that returns the same type that it was performed with

For example;

const abc: number = await someTask.perform(1)
const def: string = await someTask.perform('str')

I've come up with this as the task definition;

someTask = task(async <T>(result: T): Promise<T> => {
  return Promise.resolve(result)
})

But I can't seem to get the return type from the perform call to be generic, it seems stuck as unknown. Is there a way to do what I am trying to acheive?

It's probably got something to do with writing a Task type like this, but I can't quite figure out how to apply it to the task definition..

type SomeTask<T> = Task<T, [T]>
@ombr
Copy link

ombr commented Nov 28, 2022

Hi @Techn1x,

I have the same issue on my side, I could create a sample reproduction:

import Service from '@ember/service';
import { task, timeout } from 'ember-concurrency';

export default class Test extends Service {
  createTask = task(
    { enqueue: true, maxConcurrency: 2 },
    async <H, K extends keyof H>(hash: H, key: K): Promise<H[K]> => {
      await timeout(100);
      return hash[key];
    }
  );

  async withoutTask<H, K extends keyof H>(hash: H, key: K): Promise<H[K]> {
    await timeout(100);
    return hash[key];
  }

  async test() {
    const a = await this.withoutTask({ a: 'string', b: 12 }, 'a');
    console.log(a);
    const res = await this.createTask.perform({ a: 'string', b: 12 }, 'a');
    console.log(res);
  }
}

// DO NOT DELETE: this is how TypeScript knows how to look up your services.
declare module '@ember/service' {
  interface Registry {
    test: Test;
  }
}

Let me know If I can help here.

@ombr
Copy link

ombr commented Nov 28, 2022

Hi @Techn1x,

I think this is a limit of typescript... I did a lot of trial and error on the typescript playground, and here is a workaround that could work (forcing the type manually on the task).

const f = async <H, K extends keyof H>(h: H, k: K): Promise<H[K]> => {
  return h[k];
}
const res = f({a: 'string', b: 12}, 'b');

const task = <H,K extends keyof H>(f: (...args: [H, K])=> Promise<H[K]>): {process: (h: H, k: K)=> Promise<H[K]> } => {
  return {
    process: (h: H, k: K): Promise<H[K]>=> {
      return f(h, k);
    }
  }
}

type HackedTask = { process: <H,K extends keyof H>(h: H, k: K)=> Promise<H[K]> };

const t = (task(f) as unknown) as HackedTask;

const r = t.process({ a: 'string', b: true}, 'b');

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants