-
Notifications
You must be signed in to change notification settings - Fork 10.3k
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
sourceNodes TS types inconsistent with documentation usage #23296
Comments
I can't say I've run into any problems using the TS types. The APIs that Gatsby passes into export const sourceNodes = (args: SourceNodesArgs) => {
const { actions, createNodeId, createContentDigest } = args;
} The second parameter to the function is also the same as the other endpoints. It contains the contents of the I say "mostly" because the So, basically, the type |
Yes, that's right! I ended up doing the same, although what I meant by this whole issue was to be able to just set the type on the function not on its parameters: import { GatsbyNode } from "gatsby"
export const sourceNodes: GatsbyNode['sourceNodes'] = (args) => {} Sorry if I didn't make this clear. |
Oh, I see. Yeah, you're right. That has been an issue. I'm about 99% sure it's unable to infer the argument types because of the function signature ambiguity. There's not enough for Typescript to differentiate between the various overloads. Regarding the types for gatsby/packages/gatsby/index.d.ts Lines 418 to 424 in 8ee74c1
The third type in this list is able to be differentiated by it's third parameter, so we can just ignore it for now. It is important, though, because it forces the first two types to be much looser in their types, in order for them all to fit together. As you can see, there's not a lot separating the first two except the return type. Even though all the parameter types are the same between calls, since Typescript cannot tell which overload to use, it just assigns This is a poor way to type this kind of function call, anyway, since you would have to write the return value of the function before you can get the correct types on the function parameters. Even then, since the very first return type is You can't get rid of the first type, because that is a valid value... the return type can be a promise or not, and it is very useful for people to know what functions can be asynchronous. It also doesn't help to make it a union type, All of this together basically means a discriminated union is a better choice. It actually helps Typescript figure out what function type to use, so it is able to infer the parameter types. This works for me: interface GatsbyNodeAsyncFn<T extends NodePluginArgs, R> {
(args: T): R | Promise<R>;
(args: T, options: PluginOptions): R | Promise<R>;
}
interface GatsbyNodeCallbackFn<T extends NodePluginArgs> {
(
args: T,
options: PluginOptions,
callback: PluginCallback
): void
}
type GatsbyNodeAsync<T extends NodePluginArgs, R> = GatsbyNodeAsyncFn<T, R> | GatsbyNodeCallbackFn<T>;
export interface GatsbyNode {
sourceNodes?: GatsbyNodeAsync<SourceNodesArgs, any>;
} Realistically, the same/similar basic type can be assigned to the rest of the Because of the... intended... synchronous nature of many of the endpoints, it might make sense to include types like this: interface GatsbyNodeSyncFn<T extends NodePluginArgs, R> {
(args: T): R;
(args: T, options: PluginOptions): R;
}
interface GatsbyNodeAsyncFn<T extends NodePluginArgs, R> {
(args: T): R | Promise<R>;
(args: T, options: PluginOptions): R | Promise<R>;
}
interface GatsbyNodeCallbackFn<T extends NodePluginArgs> {
(
args: T,
options: PluginOptions,
callback: PluginCallback
): void
}
type GatsbyNodeSync<T extends NodePluginArgs, R> = GatsbyNodeSync<T, R> | GatsbyNodeCallbackFn<T>;
type GatsbyNodeAsync<T extends NodePluginArgs, R> = GatsbyNodeAsyncFn<T, R> | GatsbyNodeCallbackFn<T>; It's possible to coalesce those types, too, in order to avoid having to add Sometimes it's also useful for the export you're defining to not be typed as optional. After all, you are assigning the value... why is it optional? This is an edge case though, and I've only run into it maybe once, myself. In any case, that could be fixed with a simple utility type: export type GatsbyNodeFn<T extends keyof GatsbyNode> = Required<GatsbyNode>[T]; If you wanted to file a PR to fix this, it would be really appreciated. Personally, I haven't had the time or been concerned enough about it to go fix it. If you don't want to, I'm sure that's fine too. I, or somebody else, will probably get around to it eventually. |
Hiya! This issue has gone quiet. Spooky quiet. 👻 We get a lot of issues, so we currently close issues after 30 days of inactivity. It’s been at least 20 days since the last update here. Thanks for being a part of the Gatsby community! 💪💜 |
sourceNodes?(args: SourceNodesArgs, options: PluginOptions): any
sourceNodes?(args: SourceNodesArgs, options: PluginOptions): Promise<any>
@Js-Brecht Unfortunately the actuary type of the function overload above is not function foo(): 'foo' | 'bar';
function foo(): 'bar' | baz';
function foo() {
return 'any string will be fine';
}
If we care the return value of |
I think EDIT: There are a few |
Summary
In the documentation of sourceNodes API
the following function signature is used:
But in the actual TypeScript type definition inside index.d.ts there are only the following:
This does not make sense, as the signature used in the docs does not exist in the type definition.
Motivation
TypeScript users will benefit
Steps to resolve this issue
Well the types should be updated, I didn't look into the actual code, but if it works like in the documentation then types should be updated.
Draft the doc
Open a pull request
The text was updated successfully, but these errors were encountered: