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

Enable "strict" mode for runtime code. #3899

Merged
merged 7 commits into from
Feb 19, 2020
Merged

Conversation

maxmellen
Copy link
Contributor

@maxmellen maxmellen commented Feb 6, 2020

Addresses #3324

This PR picks up where #3426 left off setting TypeScript's strict mode on by default for runtime code and updates the standard library and tests to support those changes.

@claassistantio
Copy link

claassistantio commented Feb 6, 2020

CLA assistant check
All committers have signed the CLA.

@maxmellen maxmellen force-pushed the ts-strict branch 7 times, most recently from e620c5d to 7616ec7 Compare February 7, 2020 15:05
@maxmellen
Copy link
Contributor Author

@kitsonk I finally got the CI checks to pass.

Do you think you could have a look at the changes when you get the chance?
I don't mind keeping this branch up to date with upstream changes but I'd like to get an idea if this has any chance of being merged before putting anymore time into it.

@maxmellen maxmellen requested review from ry and bartlomieju February 7, 2020 15:41
Copy link
Contributor

@kitsonk kitsonk left a comment

Choose a reason for hiding this comment

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

A few comments... we should really go out of our way to use @ts-ignore and the not null assertion. It is just "hiding" potential logic errors.

@@ -78,8 +78,8 @@ function repeat(c: string, bytes: number): Uint8Array {

test(function bufferNewBuffer(): void {
init();
const buf = new Buffer(testBytes.buffer as ArrayBuffer);
check(buf, testString);
const buf = new Buffer(testBytes!.buffer as ArrayBuffer);
Copy link
Contributor

Choose a reason for hiding this comment

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

We should use assert(testBytes) here so the not null assertion isn't required.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I only now learned about TypeScript 3.7's "assertion functions" 🙂
I'll update my PR to take advantage of that wherever possible.

@@ -16,7 +16,7 @@ testPerm({ read: true, write: true }, function chmodSyncSuccess(): void {
// Check success when not on windows
if (isNotWindows) {
const fileInfo = Deno.statSync(filename);
assertEquals(fileInfo.mode & 0o777, 0o777);
assertEquals(fileInfo.mode! & 0o777, 0o777);
Copy link
Contributor

Choose a reason for hiding this comment

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

And again, we should use assert(fileInfo.mode)

@@ -14,8 +14,8 @@ const customInspect = Deno.symbols.customInspect;
const {
Console,
stringifyArgs
// eslint-disable-next-line @typescript-eslint/no-explicit-any
} = Deno[Deno.symbols.internal] as any;
// @ts-ignore
Copy link
Contributor

Choose a reason for hiding this comment

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

Was there another reason to change this? We should keep the any.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The issue here is that with the noImplicitAny setting set to true (implicitly turned on by the "strict" flag), TypeScript won't allow indexing Deno with Deno.symbols.internal without adding that symbol as an index in Deno's type declaration.

Another issue there is that I'm not sure that it's possible to add a computed property to a namespace. The only way I could think of to make this work would be to change Deno into a const like in this example. (Note this example will only type check but won't run.)

Do you think it's worth updating the Deno type declaration as described? I'm a bit conflicted because I think it makes sense for Deno to be a namespace and I suppose this internal symbol wouldn't be used by user code. What do you think?

Copy link
Contributor

Choose a reason for hiding this comment

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

Ok, understand now. Yeah, I think there are potentially ways, but I wouldn't want to hold up this PR. Only minor suggestion would be to put some comment after the @ts-ignore so our future selfs can understand what is going on.

Suggested change
// @ts-ignore
// @ts-ignore typescript doesn't support symbols as indexes

@@ -306,6 +306,7 @@ test(function consoleTestCallToStringOnLabel(): void {
for (const method of methods) {
let hasCalled = false;

// @ts-ignore
Copy link
Contributor

Choose a reason for hiding this comment

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

There should be a way to type it so we don't need the ignore.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Similarly to #3899 (comment), the time of the argument passed to console[method] still wouldn't be correct so I'm not sure how to improve on this.

Copy link
Contributor

Choose a reason for hiding this comment

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

I think you would have to do something like to remove the @ts-ignore:

const methods: Array<keyof Console> = ["count", "countReset", "time", "timeLog", "timeEnd"];

Copy link
Contributor Author

Choose a reason for hiding this comment

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

If I type methods as Array<keyof typeof Console> (apparently Console refers to a value in this context) I then get the following error:

error TS7053: Element implicitly has an 'any' type because expression of type 'string | number | symbol' can't be used to index type 'Console'.
  No index signature with a parameter of type 'string' was found on type 'Console'.

► file:///Users/max/Developer/deno/cli/js/console_test.ts:310:5

310     console[method]({
        ~~~~~~~~~~~~~~~

And even if we got over that error, then we'd have the issue that { toString(): void { hasCalled = true; } } wouldn't be considered a valid argument to these functions anyway (for instance, count only accepts a string), so I think the best thing to do is switch methods back to implicitly be of type string[] as before my changes and keep the @ts-ignore.

Copy link
Contributor

Choose a reason for hiding this comment

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

🤷‍♂ ok! you win! :-D

@@ -464,7 +465,7 @@ test(function consoleGroupWarn(): void {
console.warn("6");
console.warn("7");
assertEquals(
both.toString(),
both!.toString(),
Copy link
Contributor

Choose a reason for hiding this comment

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

and assert(both) prior to this.

@@ -523,7 +523,7 @@ test(async function testReadRequestError(): Promise<void> {
assert(test.headers != null);
assertEquals(err, undefined);
assertNotEquals(req, Deno.EOF);
for (const h of test.headers) {
for (const h of test.headers!) {
Copy link
Contributor

Choose a reason for hiding this comment

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

shouldn't be needed because of the assert???

@@ -1 +1,2 @@
// @ts-ignore
window["global"] = window;
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
window["global"] = window;
globalThis["global"] = globalThis;

Not your problem, but I didn't realise this was there, also I suspect we need in here:

global {
  var global: typeof globalThis;
}

So that it can be augmented properly without needing to ignore.

@@ -384,7 +388,7 @@ class Module {

Module._cache[filename] = module;
if (parent !== undefined) {
relativeResolveCache[relResolveCacheIdentifier] = filename;
relativeResolveCache[relResolveCacheIdentifier!] = filename;
Copy link
Contributor

Choose a reason for hiding this comment

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

assert(relResolveCacheIdentifier) prior to this

@@ -331,14 +331,14 @@ export function join(...paths: string[]): string {
let needsReplace = true;
let slashCount = 0;
assert(firstPart != null);
if (isPathSeparator(firstPart.charCodeAt(0))) {
if (isPathSeparator(firstPart!.charCodeAt(0))) {
Copy link
Contributor

Choose a reason for hiding this comment

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

the assertion should be working here so the not null assertion isn't needed...

@@ -24,7 +24,7 @@ export function deepAssign(
if (typeof target[key] !== `object` || !target[key]) {
target[key] = {};
}
deepAssign(target[key] as Record<string, unknown>, value);
deepAssign(target[key] as Record<string, unknown>, value!);
Copy link
Contributor

Choose a reason for hiding this comment

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

assert(value) here or deepAssign should be accepting undefined.

Copy link
Contributor

Choose a reason for hiding this comment

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

So we should be able to remove the not null assert?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yep, my bad :)

@maxmellen maxmellen force-pushed the ts-strict branch 5 times, most recently from cc1f46c to 3674746 Compare February 11, 2020 15:20
@maxmellen
Copy link
Contributor Author

@kitsonk I've updated my PR to take in account your comments. I've also raised questions/concerns to some of your comments.
I rebased my branch on master to stay up to date, and to keep things easy to review I've split the bulk of my work in 3 commits:

  • 16ab35c is my work as you initially reviewed it rebased onto master with the git conflicts fixed
  • f9eccc4 addresses your review comments where I haven't raised questions/concerns of my own
  • 3674746 adds support for strict mode in the code that was added to master since your review

@bartlomieju
Copy link
Member

@maxmellen awesome work; thank you! I resolved some minor conflict and gonna merge it once CI gets green.

@maxmellen
Copy link
Contributor Author

Hey @bartlomieju!
Just rebased and fixed the latest issues.
My changes since you had a look at my PR are contained in this commit: b499431.
CI passes but I'm not sure why the CLA assistant isn't reporting its status. You should be able to see that I signed it earlier.

@bartlomieju
Copy link
Member

@kitsonk can you take another look?

Copy link
Contributor

@kitsonk kitsonk left a comment

Choose a reason for hiding this comment

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

Thanks! A few comments, but nothing critical.

@@ -14,8 +14,8 @@ const customInspect = Deno.symbols.customInspect;
const {
Console,
stringifyArgs
// eslint-disable-next-line @typescript-eslint/no-explicit-any
} = Deno[Deno.symbols.internal] as any;
// @ts-ignore
Copy link
Contributor

Choose a reason for hiding this comment

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

Ok, understand now. Yeah, I think there are potentially ways, but I wouldn't want to hold up this PR. Only minor suggestion would be to put some comment after the @ts-ignore so our future selfs can understand what is going on.

Suggested change
// @ts-ignore
// @ts-ignore typescript doesn't support symbols as indexes

@@ -306,6 +306,7 @@ test(function consoleTestCallToStringOnLabel(): void {
for (const method of methods) {
let hasCalled = false;

// @ts-ignore
Copy link
Contributor

Choose a reason for hiding this comment

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

I think you would have to do something like to remove the @ts-ignore:

const methods: Array<keyof Console> = ["count", "countReset", "time", "timeLog", "timeEnd"];

@@ -4,8 +4,11 @@ import { test, assertEquals } from "./test_util.ts";
test(function addEventListenerTest(): void {
const document = new EventTarget();

// @ts-ignore
Copy link
Contributor

Choose a reason for hiding this comment

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

Either way, as long as we put something in there that says something like "tests ignoring the type system for resilience"

on(type, callback?, options?): void {
on(
type: string,
callback: (e: Event) => void,
Copy link
Contributor

Choose a reason for hiding this comment

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

Sorry, callback was optional (bad typing) before the types were added, now it is required.

@@ -36,7 +36,9 @@ test(function formDataParamsGetSuccess(): void {
formData.append("a", "true");
formData.append("b", "false");
formData.append("a", "null");
// @ts-ignore
Copy link
Contributor

Choose a reason for hiding this comment

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

Yeah, we don't want to deviate, so commenting again of testing contra the typings.

@@ -110,6 +114,7 @@ test(function formDataParamsArgumentsCheck(): void {
let hasThrown = 0;
let errMsg = "";
try {
// @ts-ignore
Copy link
Contributor

Choose a reason for hiding this comment

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

Understood.

name1: "value1",
name2: "value2",
name3: "value3",
// @ts-ignore
Copy link
Contributor

Choose a reason for hiding this comment

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

Understood.

@@ -39,8 +39,8 @@ testPerm({ read: true }, async function resourcesFile(): Promise<void> {
Object.keys(resourcesAfter).length,
Object.keys(resourcesBefore).length + 1
);
const newRid = Object.keys(resourcesAfter).find((rid): boolean => {
const newRid = +Object.keys(resourcesAfter).find((rid): boolean => {
Copy link
Contributor

Choose a reason for hiding this comment

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

Yeah, ok... I know Object.keys() doesn't always produce helpful types.

@@ -24,7 +24,7 @@ export function deepAssign(
if (typeof target[key] !== `object` || !target[key]) {
target[key] = {};
}
deepAssign(target[key] as Record<string, unknown>, value);
deepAssign(target[key] as Record<string, unknown>, value!);
Copy link
Contributor

Choose a reason for hiding this comment

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

So we should be able to remove the not null assert?

@maxmellen
Copy link
Contributor Author

Hey @bartlomieju, @kitsonk, I rebased my work on master and addressed your comments in my latest commit!

Copy link
Member

@bartlomieju bartlomieju left a comment

Choose a reason for hiding this comment

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

Thanks @maxmellen - massive work!

Copy link
Member

@ry ry left a comment

Choose a reason for hiding this comment

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

LGTM

@ry ry merged commit 9012556 into denoland:master Feb 19, 2020
caspervonb pushed a commit to caspervonb/deno_std that referenced this pull request Jan 21, 2021
Fixes denoland/deno#3324 

Co-authored-by: Kitson Kelly <me@kitsonkelly.com>
caspervonb pushed a commit to caspervonb/deno_std that referenced this pull request Jan 24, 2021
Fixes denoland/deno#3324 

Co-authored-by: Kitson Kelly <me@kitsonkelly.com>
caspervonb pushed a commit to caspervonb/deno_std that referenced this pull request Jan 24, 2021
Fixes denoland/deno#3324 

Co-authored-by: Kitson Kelly <me@kitsonkelly.com>
caspervonb pushed a commit to caspervonb/deno_std that referenced this pull request Jan 24, 2021
Fixes denoland/deno#3324 

Co-authored-by: Kitson Kelly <me@kitsonkelly.com>
caspervonb pushed a commit to caspervonb/deno_std that referenced this pull request Jan 31, 2021
Fixes denoland/deno#3324 

Co-authored-by: Kitson Kelly <me@kitsonkelly.com>
caspervonb pushed a commit to caspervonb/deno_std that referenced this pull request Jan 31, 2021
Fixes denoland/deno#3324 

Co-authored-by: Kitson Kelly <me@kitsonkelly.com>
caspervonb pushed a commit to caspervonb/deno_std that referenced this pull request Jan 31, 2021
Fixes denoland/deno#3324 

Co-authored-by: Kitson Kelly <me@kitsonkelly.com>
caspervonb pushed a commit to caspervonb/deno_std that referenced this pull request Jan 31, 2021
Fixes denoland/deno#3324 

Co-authored-by: Kitson Kelly <me@kitsonkelly.com>
caspervonb pushed a commit to caspervonb/deno_std that referenced this pull request Feb 1, 2021
Fixes denoland/deno#3324 

Co-authored-by: Kitson Kelly <me@kitsonkelly.com>
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

Successfully merging this pull request may close these issues.

5 participants