-
Notifications
You must be signed in to change notification settings - Fork 335
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
Review and guard all missing fields/attributes #4323
Conversation
📋 StatsFile sizes
Modules
View stats and visualisations on the review app Action run for 50eb86e |
700d2b5
to
f08332b
Compare
f08332b
to
9991e2d
Compare
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.
Most of the changes look good to me 🙌🏻 After a deeper look, this adds a lot of extra if
s and ||
so thinking this warrants a wider discussion across @alphagov/design-system-developers.
In quite a few places it looks like we're adding code branches that'll never run, though, so I've added a few questions to try and understand why they're needed. I'm worried that to please TypeScript's strict mode (in #4106), we're having to add if
s (or ||
) of which we know the result for sure (but TypeScript doesn't) 😬
@@ -132,7 +132,7 @@ export class CharacterCount extends GOVUKFrontendComponent { | |||
}) | |||
|
|||
// Determine the limit attribute (characters or words) | |||
this.maxLength = this.config.maxwords || this.config.maxlength | |||
this.maxLength = this.config.maxwords || this.config.maxlength || Infinity |
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.
question Given how we validate the configuration, we'll never reach the || Infinity
, I think. What's requiring us to keep it?
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.
Ah it's only moved it from the class field to here to make the compiler happy there's no undefined
Perhaps when we pick up #4230 we can look at CharacterCountConfig
becoming Required<CharacterCountConfig>
when all fields are validated?
Then the compiler will know a fallback is no longer needed
if (!this.$showAllButton || !this.$showAllText || !this.$showAllIcon) { | ||
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.
question We're creating these elements ourselves, what's requiring us to add this early 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.
Ah we discussed via Slack thread to use silent returns (not errors) for self-created elements
I've been running ESLint @typescript-eslint/stylistic-type-checked
with @domoscargin in #4106 so we can teach ESLint to be aware of types. These three are all null
at instantiation
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.
Returning rather than throwing is fine as we're creating these elements, as discussed on the Slack thread.
Shame TypeScript needs an extra nudge leading to us checking things we do know exist 😔
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 it's a shame, but good to be consistent
Alternatively we could consider getters and avoid null
defaults entirely?
Here's a diff of what that would look like:
null-checks...null-checks-getters
if (!this.mql || !this.$menu || !this.$menuButton) { | ||
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.
question I think this will never happen:
- We early return if
this.$menu
is falsy - We throw if
this.$menu
exists andthis.$menuButton
is falsy - And if we haven't thrown, we create
this.mql
ourselves
What's requiring us to add this early 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.
Same as we discussed via Slack thread again
Don't forget that this.$menu
being falsy causes this.mql
to stay as null
Unlike in Tabs, the compiler spotted that this.mql
isn't always set in the constructor
Can see all these with strict mode turned on in packages/govuk-frontend/tsconfig.build.json
{
"extends": "../../tsconfig.base.json",
"include": ["./src/govuk/**/*.mjs"],
"exclude": ["**/*.test.*"],
"compilerOptions": {
"lib": ["ESNext", "DOM"],
+ "strict": true,
"target": "ES2015",
"types": ["node"]
}
}
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.
As an alternative, I've mentioned getters in #4323 (comment)
Changing this.mql
to a getter (without a setter) ensures it only runs when first accessed:
get mql() {
if (!this._mql) {
this._mql = window.matchMedia('(min-width: 48.0625em)')
}
return this._mql
}
9991e2d
to
50b87e2
Compare
50b87e2
to
546865c
Compare
08ea909
to
54dafc9
Compare
546865c
to
86076b1
Compare
86076b1
to
c2d54b5
Compare
@romaricpascal I've split this PR into separate commits to show what each change is for Agree that - ariaLabelParts.push(($summary.textContent || '').trim())
+ ariaLabelParts.push(`${$summary.textContent}`.trim()) But this is only necessary when running the TypeScript compiler with From the mdn Node page:
It's a shame the compiler can't filter out other Node types that aren't possible here Update: I've moved these ones to the strict mode PR |
c2d54b5
to
79b4285
Compare
79b4285
to
4fb611f
Compare
These have always been assigned since `init()` was removed
4fb611f
to
50eb86e
Compare
@romaricpascal @domoscargin I've updated this PR to move anything "new" or for discussion into: This PR now includes only guards we've used elsewhere |
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.
Cheers for reducing the scope of it to the less controversial changes. Happy with that ⛵ .
I'm warming up to that getter pattern as well, it's quite neat. On your branch, it make the build of the elements of the accordion neatly encapsulated, on top of fixing the null
issue.
Review and guard all missing fields/attributes
Ahead of #4036 I've spent some time reviewing all optional things accessed without guards
We should follow this PR up with any extra errors we'd like to throw, although I've already split out:
HTMLAnchorElement
button and clearly guard all dynamic fields #4321getFragmentFromUrl()
to common utilities #4320For example, in PR #4320 we've identified tab links without hash fragments (already handled in Skip link)
Missing elements, attributes etc
null
defaultnull
return values not handlednull
null
astypeof value === 'object'