-
Notifications
You must be signed in to change notification settings - Fork 3.7k
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
fix: Fix compilation errors under Closure's strict mode #6073
Conversation
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.
Phew! There's a lot here.
core/block_animations.js
Outdated
const percent = ms / DURATION; | ||
|
||
if (percent > 1) { | ||
group.skew_ = ''; | ||
group.setAttribute('data-skew', ''); |
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 looks like you're just storing the skew data on the DOM between steps. Writing to and reading from the DOM can be slow.
Please confirm that this is the same number of writes as the previous code. In future we can clean it up to use local variables instead of storing data on the DOM.
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 we should look for an alternate solution here for another reason as well.
The core issue here is type safety. By setting and accessing random properties on an otherwise well-defined type, we are ignoring type safety. Moving those random properties to a data attribute does not solve the type safety issue, it just moves it to a place where Closure (and eventually TypeScript) cannot yell at us about the issue.
So I would prefer to see an alternate solution such as using a local variable / additional parameter (if this property is not used outside this class), or otherwise defining an actually useful type. In TypeScript there is the intersection type which seems fine for this (see this example of adding the honey property to an Animal: https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#differences-between-type-aliases-and-interfaces).
If we are just going to disable the type safety checking anyway then we might as well just cast to any
instead of using the dom to avoid the check. That would at least be trackable / lintable and easier to follow up on later to make improvements.
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 calling this out. This definitely does write to the DOM more, and you're also quite right that this doesn't actually fix things from a type safety perspective. It seems like I could just use a local variable for skew that gets passed to the recursive function call, but the skew also seems to be used when when dragging a block or comment in a workspace without a drag surface. From a cursory glance I think removing it means that the wiggle wouldn't happen on a drag surface-less workspace; perhaps that's enough of an edge case we can live with it? If not I'll probably opt for the any (well, ? for now) cast as you suggested.
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.
Go for any to avoid changes in behaviour, but file an issue to follow up and mark it as a P1 for this quarter.
core/rendered_connection.js
Outdated
@@ -296,13 +298,15 @@ class RenderedConnection extends Connection { | |||
// Vertical line, puzzle tab, vertical line. | |||
const yLen = renderConstants.TAB_OFFSET_FROM_TOP; | |||
steps = svgPaths.moveBy(0, -yLen) + svgPaths.lineOnAxis('v', yLen) + | |||
shape.pathDown + svgPaths.lineOnAxis('v', yLen); | |||
(/** @type {PuzzleTab} */ (shape)).pathDown + |
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 is tricky. It's not guaranteed to be a puzzle tab. It's just guaranteed to have a pathDown
property. Same issue with the notch.
@@ -1237,13 +1237,13 @@ class WorkspaceSvg extends Workspace { | |||
this.cachedParentSvgSize_.width = width; | |||
// This is set to support the public (but deprecated) Blockly.svgSize | |||
// method. | |||
svg.cachedWidth_ = width; |
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.
TODO as a followup: delete svgSize and everything associated. Its deprecation window has passed, but deletion should be a standalone PR.
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 this is a lot of work and I definitely respect that, so feel free to push back on this feedback.
But in general I would prefer to see fewer casts, and instead choose one of the following as appropriate
- Better type choice from the beginning (like you already did by changing Element to HTMLElement, etc) or at the source
- More type refinement checks instead (check if the thing is an instanceof another thing, then Closure and TypeScript compilers both know how to handle that smartly with no casts)
- some special cases could probably use more general improvements, like checking the type instead of using
isCollapsible
, but i think those cases are more for improving in the future rather than changing here.
casts will still be necessary and fine in some cases (e.g. the document.createElement
calls that can't statically return the correct / more narrow type) but there are others where I think we could improve, though again I acknowledge that is more work and probably requires digging in on a more case-by-case basis.
also I didn't catch all of them but all of the casts to non-primitive types should have nullability modifiers. i think we must have a setting turned off to do strict null checks because otherwise closure should definitely complain when you cast something to implicitly nullable (with no modifier) and then immediately assume it's actually not null. but i think this will cause problems because (hopefully) TypeScript will yell about that, as it should.
core/block_animations.js
Outdated
const percent = ms / DURATION; | ||
|
||
if (percent > 1) { | ||
group.skew_ = ''; | ||
group.setAttribute('data-skew', ''); |
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 we should look for an alternate solution here for another reason as well.
The core issue here is type safety. By setting and accessing random properties on an otherwise well-defined type, we are ignoring type safety. Moving those random properties to a data attribute does not solve the type safety issue, it just moves it to a place where Closure (and eventually TypeScript) cannot yell at us about the issue.
So I would prefer to see an alternate solution such as using a local variable / additional parameter (if this property is not used outside this class), or otherwise defining an actually useful type. In TypeScript there is the intersection type which seems fine for this (see this example of adding the honey property to an Animal: https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#differences-between-type-aliases-and-interfaces).
If we are just going to disable the type safety checking anyway then we might as well just cast to any
instead of using the dom to avoid the check. That would at least be trackable / lintable and easier to follow up on later to make improvements.
core/bubble_dragger.js
Outdated
if (this.draggingBubble_.isComment) { | ||
// TODO (adodson): Resolve build errors when requiring | ||
// WorkspaceCommentSvg. | ||
if (this.draggingBubble_ instanceof WorkspaceCommentSvg) { | ||
const event = /** @type {!CommentMove} */ | ||
(new (eventUtils.get(eventUtils.COMMENT_MOVE))( | ||
/** @type {!WorkspaceCommentSvg} */ (this.draggingBubble_))); |
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 don't think you should need this cast either inside your new type refinement check. also it's weird to me that (new (eventUtils.get(eventUtils.COMMENT_MOVE))
would need to be cast... why doesn't that just return the correct type?
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.
Done, thanks! The CommentMove cast appears to be necessary because eventUtils.get returns the Abstract event class. I agree it would be nice if it used generics but that'd be a breaking change and probably better suited for post-TS cleanup?
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 can eventually do something like this: https://www.typescriptlang.org/docs/handbook/dom-manipulation.html#documentcreateelement
@@ -186,7 +191,7 @@ class Drawer { | |||
this.positionExternalValueConnection_(row); | |||
|
|||
const pathDown = (typeof input.shape.pathDown === 'function') ? | |||
input.shape.pathDown(input.height) : | |||
(/** @type {function(number)} */ (input.shape.pathDown))(input.height) : |
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 one feels weird to me too. i don't feel i've seen a typecast just so we can tell it what type the parameter will be. seems like closure knowing it's a function should be enough but i guess not.
@maribethb -- I agree with your points where we can use Where larger changes are required, including for type safety, I prefer to file issues and mark them as P1 for this quarter. The internal typescript migration guide says:
If Aaron can get these errors out of the way, it lets him find the next blocker for migration, and we need to find those as early as possible. I can follow up and do cleanup in separate PRs--which also makes it easier to undo if the cleanup changes runtime behaviour and causes bugs. |
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 looks better. Please add !
to types in zelos/drawer.js
, measurables/inline_input.js
, common/marker_svg.js
, common/drawer.js
, and zelos/info.js
.
The basics
npm run format
andnpm run lint
The details
Resolves
Progress towards #5857
Proposed Changes
This PR resolves many compilation errors in core when run under Closure's strict mode.
Reason for Changes
Blockly needs to compile cleanly under strict mode before it can be migrated to TS.
Test Coverage
Test suite passes.