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

@types/node: enable strictnullchecks, fix resulting issues #20542

Closed
wants to merge 9 commits into from

Conversation

akdor1154
Copy link
Contributor

@akdor1154 akdor1154 commented Oct 13, 2017

Please fill in this template.

  • Use a meaningful title for the pull request. Include the name of the package modified.
  • Test the change in your own code. (Compile and run.)
  • Follow the advice from the readme.
  • Avoid common mistakes.
  • Run npm run lint package-name (or tsc if no tslint.json is present).

Select one of these and delete the others:

If changing an existing definition:

Update @types/node to successfully work with strictNullChecks: true. Also var -> let in node-tests.ts. The first commit just fixes the "use before declaration" errors local to node-tests, the rest go on to fix the actual declaration problems detected as a result.

I am a bit confused that I was unable to find any existing discussion over this, sorry if I am unwittingly stomping all over existing drama.

-- Jarrad

@dt-bot
Copy link
Member

dt-bot commented Oct 13, 2017

types/node/index.d.ts

to authors (@DefinitelyTyped/DefinitelyTyped @parambirs @tellnes @WilcoBakker @octo-sniffle @smac89 @Flarna @mwiktorczyk @wwwy3y3 @Tyriar @DeividasBakanas @kjin @alvis Microsoft TypeScript (account can't be detected)). Could you review this PR?
👍 or 👎?

@akdor1154
Copy link
Contributor Author

akdor1154 commented Oct 13, 2017

Open question - I've fixed up definitions for errbacks in the tests to be (error: Error|null, result: Result). In theory, this is what Node errbacks do by convention. However, I don't think anybody would like to trawl through the node codebase and make sure that nobody ever ever sends an undefined in case of an error.

Hence, should the definitions of Node builtin modules be changed to pass (error: Error | null | undefined) in general? This question is probably (hopefully :) ) too broad for this PR, but it is something we might have to think about if it's accepted (as it might encourage user code like if (err === null) { }, which I wouldn't trust for reasons above).

@typescript-bot typescript-bot added the Popular package This PR affects a popular package (as counted by NPM download counts). label Oct 13, 2017
@typescript-bot
Copy link
Contributor

@akdor1154 Please fix the failures indicated in the Travis CI log.

@@ -5036,6 +5038,7 @@ declare module "stream" {
wrap(oldStream: NodeJS.ReadableStream): Readable;
push(chunk: any, encoding?: string): boolean;
destroy(error?: Error): void;
_destroy(error: Error | null, cb: (e: Error | null) => any): void;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

actually _destroy gets the error passed to destroy so I think here we have and exception to the Error | null rule.
And I think the return type of cb should be void.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

destroy contains the call this._destroy(error || null) - https://github.com/mcollina/node/blob/master/lib/internal/streams/destroy.js#L32 .

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah yes, you are right.

_destroy(err: Error, callback: Function): void;
_write(chunk: string | Buffer | any, encoding: string, callback: (e?: Error) => any): void;
_writev(chunks: Array<{ chunk: string | Buffer, encoding: string }>, callback: Function): void;
_destroy(error: Error | null, cb: (e: Error | null) => any): void;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As in Readable.

@@ -123,7 +123,7 @@ interface NodeModule {
id: string;
filename: string;
loaded: boolean;
parent: NodeModule | null;
parent: NodeModule | undefined;
Copy link
Contributor

@Flarna Flarna Oct 13, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can remember that parent may be also null in some cases but I can't remember the exact use case.
Please adapt also the class NodeJS.Module accordingly.
At least in source I found following new Module('internal/preload', null); so null is used to init parent.

@ghost
Copy link

ghost commented Oct 16, 2017

@akdor1154 Please fix the merge conflict.
As for null vs null | undefined, I would wait until you actually see undefined coming out of node, assuming that their documentation guarantees that null should be sent instead.

@akdor1154
Copy link
Contributor Author

akdor1154 commented Oct 16, 2017

@andy-ms Documentation makes no such guarantee, convention states that null should be preferred.
Documentation varies module to module (and is sometimes entirely absent..), but for example fs states

The asynchronous form always takes a completion callback as its last argument. The arguments passed to the completion callback depend on the method, but the first argument is always reserved for an exception. If the operation was completed successfully, then the first argument will be null or undefined.

Examples generally always show error checks as a check for truthiness, if (err) { ... }.

If this were my own project the way I would type this is add a

type NodeErrBack<T, E=Error> = (error?: null | Error, result: T) => void

and use it throughout node/index.d.ts. Would that approach be acceptable?

@ghost
Copy link

ghost commented Oct 16, 2017

Sure, although I would write error: Error | null | undefined as I don't think an optional parameter can come first.

@akdor1154
Copy link
Contributor Author

akdor1154 commented Oct 16, 2017

should I add this to this PR? (it'll be a pretty big change, touching any function in node that takes a callback...)
EDIT also, are default generics allows in this?

@ghost
Copy link

ghost commented Oct 16, 2017

It can be in a separate PR.
The node types haven't updated to ts2.3 yet so they don't support default generics. We could increment the version but it would need a good reason.

@akdor1154
Copy link
Contributor Author

k, shall rebase+squash then continue discussion in a new PR.

@akdor1154
Copy link
Contributor Author

akdor1154 commented Oct 17, 2017

The failing lint in duplexer3 is a result of this pr. The reason is because the cb parameter in stream._write is now typed as => void instead of => any. The failing statement in duplexer3 is

writable._write = (input, encoding, done) => {
  if (something) {
    return done();
  }
  ..
}

which is a common pattern, but fails no-void-expression in tslint if done() => void. Does this suggest callbacks should be typed as => any and not => void?

@Flarna
Copy link
Contributor

Flarna commented Oct 17, 2017

Besides the first argument in callbacks also the second one is optional - if the first one is not null.
Would be nice if this known dependency could be modeled somehow otherwise users have to use two checks or the ! operator.
Maybe the default type should be NodeJS.ErrnoException, I have seen several complains that checking the optional errno/code properties is not allowed by typescript.
I fear stepping to typescript 2.3 could be cumbersome as it would imply that all the > 1000 dependent modules have to use also >=2.3 to my understanding.

@Flarna
Copy link
Contributor

Flarna commented Oct 17, 2017

Regarding the issue with duplexer3: I would vote against use of any in callbacks just to make lint happy. Lint should help us not we should help lint.
I think we should try to avoid any where possible.

@ghost
Copy link

ghost commented Oct 17, 2017

You don't have to change the type, you can just done(); return;.

@akdor1154
Copy link
Contributor Author

@andy-ms my point is more that return done() is idiomatic, and I don't want to create a situation where valid and idiomatic code causes a lint error. I think I would tend towards Flarna's approach that this is more a lint configuration problem though.

@ghost
Copy link

ghost commented Oct 30, 2017

It won't cause a lint error for people not using DT's lint configuration. So I agree with @Flarna to use the most accurate type possible, and users who don't want a lint error on return done(); should not use that lint rule.

@RyanCavanaugh
Copy link
Member

@akdor1154 Please fix the failures indicated in the Travis CI log.

@akdor1154 akdor1154 force-pushed the strict branch 3 times, most recently from a7f3690 to 7761e1b Compare November 1, 2017 22:58
@minestarks
Copy link
Contributor

@akdor1154 could you fix the test failures?

@minestarks
Copy link
Contributor

I'm closing this PR due to lack of activity. If you would still like to get in these changes, please open a new PR. Thank you!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Popular package This PR affects a popular package (as counted by NPM download counts).
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

6 participants