-
Notifications
You must be signed in to change notification settings - Fork 5.4k
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
Conversation
e620c5d
to
7616ec7
Compare
@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? |
There was a problem hiding this 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.
cli/js/buffer_test.ts
Outdated
@@ -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); |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
cli/js/chmod_test.ts
Outdated
@@ -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); |
There was a problem hiding this comment.
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)
cli/js/console_test.ts
Outdated
@@ -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 |
There was a problem hiding this comment.
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
.
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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.
// @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 |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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"];
There was a problem hiding this comment.
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
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🤷♂ ok! you win! :-D
cli/js/console_test.ts
Outdated
@@ -464,7 +465,7 @@ test(function consoleGroupWarn(): void { | |||
console.warn("6"); | |||
console.warn("7"); | |||
assertEquals( | |||
both.toString(), | |||
both!.toString(), |
There was a problem hiding this comment.
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.
std/http/server_test.ts
Outdated
@@ -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!) { |
There was a problem hiding this comment.
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???
std/node/global.ts
Outdated
@@ -1 +1,2 @@ | |||
// @ts-ignore | |||
window["global"] = window; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
std/node/module.ts
Outdated
@@ -384,7 +388,7 @@ class Module { | |||
|
|||
Module._cache[filename] = module; | |||
if (parent !== undefined) { | |||
relativeResolveCache[relResolveCacheIdentifier] = filename; | |||
relativeResolveCache[relResolveCacheIdentifier!] = filename; |
There was a problem hiding this comment.
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
std/path/win32.ts
Outdated
@@ -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))) { |
There was a problem hiding this comment.
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...
std/util/deep_assign.ts
Outdated
@@ -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!); |
There was a problem hiding this comment.
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
.
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep, my bad :)
cc1f46c
to
3674746
Compare
@kitsonk I've updated my PR to take in account your comments. I've also raised questions/concerns to some of your comments. |
@maxmellen awesome work; thank you! I resolved some minor conflict and gonna merge it once CI gets green. |
Hey @bartlomieju! |
@kitsonk can you take another look? |
There was a problem hiding this 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.
cli/js/console_test.ts
Outdated
@@ -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 |
There was a problem hiding this comment.
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.
// @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 |
There was a problem hiding this comment.
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"];
cli/js/event_target_test.ts
Outdated
@@ -4,8 +4,11 @@ import { test, assertEquals } from "./test_util.ts"; | |||
test(function addEventListenerTest(): void { | |||
const document = new EventTarget(); | |||
|
|||
// @ts-ignore |
There was a problem hiding this comment.
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"
cli/js/event_target_test.ts
Outdated
on(type, callback?, options?): void { | ||
on( | ||
type: string, | ||
callback: (e: Event) => void, |
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
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 => { |
There was a problem hiding this comment.
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.
std/util/deep_assign.ts
Outdated
@@ -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!); |
There was a problem hiding this comment.
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?
Account for code review comments
Post-rebase fixes for strict mode
Post-rebase fixes for strict mode
Account for code review comments
Hey @bartlomieju, @kitsonk, I rebased my work on master and addressed your comments in my latest commit! |
There was a problem hiding this 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!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
Fixes denoland/deno#3324 Co-authored-by: Kitson Kelly <me@kitsonkelly.com>
Fixes denoland/deno#3324 Co-authored-by: Kitson Kelly <me@kitsonkelly.com>
Fixes denoland/deno#3324 Co-authored-by: Kitson Kelly <me@kitsonkelly.com>
Fixes denoland/deno#3324 Co-authored-by: Kitson Kelly <me@kitsonkelly.com>
Fixes denoland/deno#3324 Co-authored-by: Kitson Kelly <me@kitsonkelly.com>
Fixes denoland/deno#3324 Co-authored-by: Kitson Kelly <me@kitsonkelly.com>
Fixes denoland/deno#3324 Co-authored-by: Kitson Kelly <me@kitsonkelly.com>
Fixes denoland/deno#3324 Co-authored-by: Kitson Kelly <me@kitsonkelly.com>
Fixes denoland/deno#3324 Co-authored-by: Kitson Kelly <me@kitsonkelly.com>
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.