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
feat(Client): add conditional ready typings #6073
Conversation
I think transforming Client in a generic type is a too big change which will make a lot of problems to TS users... Why not just using something like is done with Partials? Like, create an interface called LoggedClient and pass it in events (where we're sure the client is logged). |
ef07148#diff-4f45caa500ef03d94d3c2bfa556caa1642df95d4e2b980d76b876a8fd2e8c522R283 It defaults to
That's another approach that could work; I settled on a generic type as it results in minimal overhead for existing users. i.e. just change
In some cases I think that makes sense, yeah. Like
On it :) |
Are these typing changes suitable? If so, will add them to PR. |
I would say so although you missed quite a lot of Base extensions |
|
I'm not sure I fully understand the benefit of this. If the TS user has to manually define it as TypeScript isn't "inferring" anything if I'm the one casting it to an interface where the properties aren't null, because manual casts can still be done incorrectly. |
The way I see this is that the classes extend a Base class that is already logged in so it knows the properties in client are not null, the user would not have to do any non-null asserting. |
That sounds even more incorrect. Though uncommon, I don't see anything guaranteeing that an instance of a class extending base has a logged in client. These are forced types, not inferred ones. |
You can’t really interact with Discord if you’re not logged in so anything the client receives has to be with a logged in client |
This PR adds the A potential use pattern would be:
|
The problem is that from what I can see, you're not defining it as logged in only on the Client events - you're defining it as always true on the base class itself. This simply isn't true 100% of the time. As much as I hate myself for writing terrible discord.js usage like this: const client = new Client({ intents: ["GUILDS"] });
client.token = "<token>";
const guild = await client.guilds.fetch("412130302958239745"); This code is functional, and will return a horribly useless partial Guild object. But it does work. client.on("message", message => {
message.client.destroy();
}); This had a logged in client, and now it doesn't anymore. It's still typed as To be clear, I very much do like the |
I don't know of any projects using such methods for fetching data without logging in. However, if this is something that some users do, we could remove this by making the client's managers (including
const { Client } = require("discord.js");
const client = new Client({ intents: ["GUILDS", "GUILD_MESSAGES"] });
client.on("ready", () => {
console.log("before destroy()", client.user.tag);
client.destroy();
console.log("after destroy()", client.user.tag);
});
client.login(process.env.DISCORD_TOKEN); $ node index.js
before destroy() Rikona#7979
after destroy() Rikona#7979 Calling |
True, the main problem is the advantage of that. In some places we're sure that the client is logged or that, however, some properties are not null, but we still need to use an assertion like |
If there exists cases where it is wrong, then it is wrong. Not a fan of this unless those edge cases can be fixed. |
The underlying issue seems to me to be that there is no single well-defined state in which the client is logged in aside from client events (but even those can be triggered without logging in). With this in mind, universally generalizing the
@1Computer1 @monbrey Which of these seem the best route to you? Or, do you have other alternatives? |
It seems to me actually that |
I think that creating an interface |
As per an earlier comment on that:
|
Well, in an event (that is not in our index file) we'll need to import Client probably, as we don't need to declare them but use with a function parameter, or with the |
Well you would still need to do casting either way since we can't count on event clients being logged in except for in the ready event |
Yeah, that's why it's the same IMO... Maybe creating another type will be useful for people who are asking why is there a generic, but, at the same time, we still need to use the isReady / a typecast to let TS know that the client is logged. |
Please describe the changes this PR makes and why it should be merged:
This PR adds conditional typings to the
Client
class, allowing for TypeScript to infer the ready state of the client and provide access to properties that are initialized at login, such asClient#application
andClient#user
. This also adds a client parameter to theClient.on("ready")
event, defined in typings as a ready client.This will be a major quality-of-life improvement for users of TypeScript and typings users, as it allows for access to client properties without optional chaining or non-null assertions.
Status and versioning classification: