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
Strict nulls for everything except logconsole #7657
Conversation
Thanks for making a pull request to JupyterLab! To try out this branch on binder, follow this link: |
Status: Most "core dependencies" now compile, so most errors are moving towards being in "leaf" packages. Note: To better handle typings vs. dispose, I some places change from setting the cleared variables to |
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 for tackling this!
One issue that keeps popping up for strict nulls is this:
|
For clarity, (2) will be closest to today's situation, so I will likely default to this option if no-one else chimes in. It is also not clear to me how such errored widgets will be tracked by various widget trackers. |
I think type them as not null, and when disposed, set them to |
(I think that is essentially your option 2, but using null instead of undefined.) |
Note, that the case I'm talking about is not disposal, but rather showing an error message instead: jupyterlab/packages/apputils/src/mainareawidget.ts Lines 75 to 92 in 0c2ef44
|
Status update: All packages now compile, so this can be considered a rough draft. Next is getting tests to compile. |
Tests passing locally. Once it turns green for CI, I'll rebase and restructure the commits to make reviewing easier. I'll also address the TODO comments above. |
All green, and TODOs fixed. Will do a rebase / history-rewrite to clean up commit messages and hopefully ease review. |
I see that the CC @jasongrout / @mbektasbbg |
Should not require detailed review.
These should not change the logic when operating normally, but might end up silently supressing failures instead of throwing errors in certain failure cases. On the other hand, the suppression might be what we want here.
Some of these are likely not correct, some of them are. Hard to tell, but they are unlikely to affect the public API, so punting.
These made sense to me, but might be the wrong fixes!
879c914
to
cf623f1
Compare
@@ -15,7 +15,7 @@ import { ISignal } from '@lumino/signaling'; | |||
/** | |||
* A generic interface for change emitter payloads. | |||
*/ | |||
export interface IChangedArgs<T, U extends string = string> { | |||
export interface IChangedArgs<T, OldT = T, U extends string = string> { |
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.
This commit adds an optional generic arg to allow change notifications to specify different typings for the old and new values (nice e.g. when the initial value is null
, but it can never be set back to null
after that). Note that this changes the order of the generic args (the name typing gets pushed later).
/** | ||
* Create a new VDomRenderer | ||
*/ | ||
constructor(model: T extends null ? void : T) { |
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.
This commit changes the VDomRenderer
to take the model as a constructor arg, in order to make it non-nullable. This was an easy fit here, but might give less flexibility for 3rd party renderers?
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 reason not to have it in the constructor was because setting the model calls override-able methods, which would not call overrridden versions of those methods in the subclass.
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.
No test failures 😉
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.
Do you want to revert this behavior then? Or perhaps have the constructor call a protected setter method (or something similar)?
@@ -83,9 +83,9 @@ export class DSVModel extends DataModel implements IDisposable { | |||
this._parseAsync(); | |||
|
|||
// Cache the header row. | |||
if (header === true && this._columnCount > 0) { | |||
if (header === true && this._columnCount! > 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.
It was really hard to track down when the various variables in the CSV viewer code was null/undefined, so for now I simply added non-null asserts everywhere. This commit has a lot of other such asserts as well, and basically maintains the status-quo, even if they might have revealed some incorrect nullable handling. The main point to review this for is if any fix of an incorrect call here would cause an API breakage (we could probably put those as "fixing" typings as a bug, so might be ok).
@@ -90,10 +90,11 @@ export namespace Printing { | |||
await resolveWhenLoaded(iframe); | |||
} else { | |||
iframe.src = 'about:blank'; | |||
await resolveWhenLoaded(iframe); |
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 this resolves a possible race condition?
user: key in user ? copy(user[key]) : undefined | ||
composite: | ||
composite[key] !== undefined ? copy(composite[key]!) : undefined, | ||
user: user[key] !== undefined ? copy(user[key]!) : 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.
I think this should behave correctly, but it is a logic change.
if (ncols === undefined) { | ||
if (nrows !== 1) { | ||
throw new Error('Error parsing default number of columns'); | ||
} |
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.
@jasongrout Will these be logically equivalent?
body: 'No context found for current widget!', | ||
buttons: [Dialog.okButton()] | ||
}); | ||
} |
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 added a bunch of failure dialogs like this here, based on the pattern for one of the commands. Not sure if silent failure is better?
@@ -252,7 +252,7 @@ export class DocumentWidgetManager implements IDisposable { | |||
* | |||
* @param widget - The target widget. | |||
*/ | |||
protected setCaption(widget: Widget): Promise<void> { | |||
protected async setCaption(widget: Widget): Promise<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.
This should fix the return type from the naked return
statements below from untitled
to Promise<void>
. I assume this is a fix, and not an API break...
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.e. I assume the return type should stay the currently typed Promise<void>
, not the currently implemented Promise<void> | undefined
.
@@ -270,7 +270,7 @@ function activateLogConsole( | |||
} else { | |||
source = null; | |||
} | |||
if (logConsoleWidget) { | |||
if (logConsolePanel) { |
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 assume this is a fix, and not a break...
outputArea.rendermime = change.newValue; | ||
} else { | ||
outputArea.dispose(); | ||
} |
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'm unsure why I made this change, but it think it made sense at the time. Please review carefully...
@@ -336,6 +336,7 @@ export function addCommands( | |||
Terminal = (await Private.ensureWidget()).Terminal; | |||
} catch (err) { | |||
Private.showErrorMessage(err); | |||
return; |
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 assume this is a fix, and not a break...
implements IStateDB<T> { | ||
export class StateDB< | ||
T extends ReadonlyPartialJSONValue = ReadonlyPartialJSONValue | ||
> implements IStateDB<T> { |
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.
Here I switch the StateDB to use partial types as well, as that seems to be needed / more accurate. On the other hand, it is harder to tighten up this types later if we incorrectly relax them now. Thoughts? CC @afshin
@@ -348,7 +348,7 @@ function activateEditorCommands( | |||
} | |||
modeMenu.addItem({ | |||
command: CommandIDs.changeMode, | |||
args: { ...spec } | |||
args: { ...spec } as any // TODO: Casting to `any` until lumino typings are fixed |
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.
Xref this comment: jupyterlab/lumino#32 (comment)
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.
Heads up, #7252 caused a bunch of conflicts. |
@vidartf I looked into this but I don't see an easy solution. Your plan to disable null checks for log console sounds good to me, at least until we have a better solution. |
I've merged in master, and it is all green again. (one outstanding comment from @blink1073 above to resolve) |
Merging and iterating on this, since it affects so many packages. Thanks! |
References
Continues #7607.
Code changes
Turns on strict null checks for all packages except services (to avoid double work related to #7252).
User-facing changes
None, maybe some bugfixes.
Backwards-incompatible changes
Typings on some public API gets "fixed", but these are sweeping enough that it should be considered backwards incompatible.
TODO: