not-an-aardvark / snoowrap

A JavaScript wrapper for the reddit API
MIT License
1.01k stars 125 forks source link

Type error with async/await #221

Open Moebits opened 4 years ago

Moebits commented 4 years ago

I updated to version 1.19.0 of the package (which includes typings). I get the following error when trying to await promises (Typescript):

Type is referenced directly or indirectly in the fulfillment callback of its own 'then' method

Here are the snippets that receive the error:

const user = await reddit.getUser(query.trim()).fetch() //param is string
const post = await reddit.getRandomSubmission()
const post = await reddit.getSubmission(postIDS[i]).fetch() //param is string
const posts = await reddit.getSubreddit(subreddit).getRandomSubmission() //param is string

This error seems to come from the package. While I don't see a mention of async/await in the docs, it did work perfectly before...

Venefilyn commented 4 years ago

Could you pinpoint where you're getting this? Or is this happening on all functions you mentioned?

Venefilyn commented 4 years ago

I've tried looking at some of the functions you mentioned but all type definitions are correct

Moebits commented 4 years ago

For reference, the entire file where I used snoowrap is here: https://github.com/Tenpi/Kisaragi/blob/master/commands/website/reddit.ts

I also found another issue from the DefinitelyTyped repo that reports the same: https://github.com/DefinitelyTyped/DefinitelyTyped/issues/33139

I'm not entirely sure, but I think that the error has to do with promises that resolve to themselves. Using .then() syntax works perfectly, however. Don't worry too much about it though, I will just have typescript ignore the lines that give the error.

Venefilyn commented 4 years ago

That's unsettling.. does the error go away if you explicitly append .fetch()?

garyking commented 4 years ago

I can confirm this issue. Code example is below, with the error message in the comments.

import Snoowrap from 'snoowrap';

async function main(): Promise<void> {
  const snoowrap = new Snoowrap(<login info>);
  const sub = snoowrap.getSubreddit('pics');
  /**
   * (method) RedditContent<Subreddit>.fetch(): Promise<Subreddit> 
   *
   * Type is referenced directly or indirectly in the fulfillment callback of
   * its own 'then' method.ts(1062)
   *
   */
  const subreddit = await sub.fetch();
  const newPosts = await subreddit.getNew();

  console.log(newPosts);
}

main();
benjick commented 4 years ago

Anything new on this? PS thanks for a great package 👍

prmichaelsen commented 3 years ago

Does anyone have an update on this? Even trying to work around it with fetch or then yields the same error.

bluecomm42 commented 3 years ago

I'm also running into this issue. Is it really necessary for RedditContent to extend Promise? I feel it would be cleaner both from a typescript perspective and just for separation of concerns in general to have promised returns be explicit rather than implicit. Such a change would require a version bump, as it wouldn't be backwards compatible, but it would save my editor from constantly trying to correct comment.reply(...) to (await comment).reply(...).

franklinharvey commented 3 years ago

Feel free to check out #296 . The issue is that the objects/RedditContent.d.ts declares

class RedditContent<T> extends Promise<T>

and it should just be

class RedditContent<T>

This works now without changing the underlying .js, this type declaration was just incorrect.

Tyrrrz commented 2 years ago

Another hack/workaround for this is to use Omit<> type in TypeScript:

const unpromise = async <T>(promise: Promise<T>) => {
  const result = await promise;
  return result as Omit<T, 'then' | 'catch' | 'finally'>;
};

// This produces an error
const comment = await reddit.getComment('...');

// This does not produce an error
const comment = await unpromise(reddit.getComment('...'));
Loeffeldude commented 2 years ago

A better quick fix is putting this in a ts file in your project. This way you don't need to cast or use a function. This then fixes it globally.

import * as snoowrap from "snoowrap";

declare module "snoowrap" {
  class RedditContent<T> {
    then: undefined;
    catch: undefined;
    finally: undefined;
  }
}
amosbastian commented 2 years ago

A better quick fix is putting this in a ts file in your project. This way you don't need to cast or use a function. This then fixes it globally.

import * as snoowrap from "snoowrap";

declare module "snoowrap" {
  class RedditContent<T> {
    then: undefined;
    catch: undefined;
    finally: undefined;
  }
}

It doesn't set the return type to a promise so await will have a squiggly line