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

refactor: minor ESLint improvements #5981

Merged
merged 3 commits into from
Dec 3, 2021
Merged

refactor: minor ESLint improvements #5981

merged 3 commits into from
Dec 3, 2021

Conversation

Josh-Cena
Copy link
Collaborator

Motivation

Have you read the Contributing Guidelines on pull requests?

Yes

Test Plan

Lint

@Josh-Cena Josh-Cena added the pr: polish This PR adds a very minor behavior improvement that users will enjoy. label Nov 21, 2021
@facebook-github-bot facebook-github-bot added the CLA Signed Signed Facebook CLA label Nov 21, 2021
@netlify
Copy link

netlify bot commented Nov 21, 2021

✔️ [V2]

🔨 Explore the source changes: bf2f29b

🔍 Inspect the deploy log: https://app.netlify.com/sites/docusaurus-2/deploys/61aa4279e8cc39000a284abd

😎 Browse the preview: https://deploy-preview-5981--docusaurus-2.netlify.app

@github-actions
Copy link

github-actions bot commented Nov 21, 2021

⚡️ Lighthouse report for the changes in this PR:

Category Score
🟠 Performance 80
🟢 Accessibility 98
🟢 Best practices 100
🟢 SEO 100
🟢 PWA 95

Lighthouse ran on https://deploy-preview-5981--docusaurus-2.netlify.app/

@github-actions
Copy link

github-actions bot commented Nov 21, 2021

Size Change: -234 kB (-26%) 🎉

Total Size: 656 kB

Filename Size Change
website/.docusaurus/globalData.json 40.1 kB +1.83 kB (+5%) 🔍
website/build/assets/css/styles.********.css 101 kB +704 B (+1%)
website/build/assets/js/main.********.js 485 kB +9.3 kB (+2%)
website/build/blog/2017/12/14/introducing-docusaurus/index.html 0 B -66.1 kB (removed) 🏆
website/build/blog/index.html 0 B -36.8 kB (removed) 🏆
website/build/docs/index.html 0 B -44 kB (removed) 🏆
website/build/docs/installation/index.html 0 B -51.7 kB (removed) 🏆
website/build/tests/docs/index.html 0 B -25.2 kB (removed) 🏆
website/build/tests/docs/standalone/index.html 0 B -21.7 kB (removed) 🏆
ℹ️ View Unchanged
Filename Size Change
website/build/index.html 29.5 kB -5 B (0%)

compressed-size-action

themeConfig: ThemeConfig;
// Why partial? To make TS correctly figure out the contravariance in parameter.
// In practice it's always normalized
themeConfig: Partial<ThemeConfig>;
Copy link
Collaborator

Choose a reason for hiding this comment

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

I don't understand what you mean here

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

From the rule documentation of @typescript-eslint/method-signature-style:

Methods are always bivariant in their argument, while function properties are contravariant in their argument under strictFunctionTypes.

Before, we had translateThemeConfig defined as method, so it's bivariant (essentially, see it as TS always doing type assertions—as long as the types fully overlap, the check passes).

Now, translateThemeConfig is a function. Functions are contravariant in their arguments, meaning that if we do...

const plugin: Plugin = themeClassic;

...TS would expect Parameters<themeClassic['translateThemeConfig']> to be a supertype of Parameters<plugin['translateThemeConfig']>. This is much safer than bivariance because it should be what you expect for functions: a function foo that accepts Dog shouldn't be assignable to a function that accepts Animal because foo might call properties that only exist on Dog.

However, {themeConfig: import('@docusaurus/theme-common').ThemeConfig} is not a supertype of {themeConfig: Record<string, unknown>}, because the former requires properties like navbar, footer, etc., while the latter, which is the one defined in the core, expects none of the properties. That means themeClassic.translateThemeConfig can, theoretically, do something specific with these properties while the core doesn't know that when calling this method and pass in a theme config without footer, causing a "cannot read from undefined" error at runtime.

In practice, themeClassic.translateThemeConfig doesn't actually demand these properties to always exist, albeit they would always. Therefore making it Partial makes TS happy and also makes it make more sense.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

"Contravariance in argument" is quite hard to explain without using this jargon, so I decided to just write that one-line hint and expect people to have some sense of what's going on instead of being fully informed...

Copy link
Collaborator

Choose a reason for hiding this comment

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

I understand what is covariance/contravariance, it's just I don't really understand why it requires Partial here

In practice, this method receives a normalized/validated themeConfig. If validation ensures that themeConfig.navbar is mandatory, we shouldn't have to deal with a partial theme config and handle undefined that can't happen in practice.

The main problem is that we have no way for the theme to declare its ThemeConfig param, we should have a generic like Plugin<PluginContent = unknown,PluginThemeConfig = unknown> and get the right ThemeConfig type injected in the method.

Not sure how easy this refactor would be, but we should add more generic types someday.

In the meantime I'll just add an adapter layer:

image

@Josh-Cena Josh-Cena added the status: awaiting review This PR is ready for review, will be merged after maintainers' approval label Dec 2, 2021
themeConfig: ThemeConfig;
// Why partial? To make TS correctly figure out the contravariance in parameter.
// In practice it's always normalized
themeConfig: Partial<ThemeConfig>;
Copy link
Collaborator

Choose a reason for hiding this comment

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

I understand what is covariance/contravariance, it's just I don't really understand why it requires Partial here

In practice, this method receives a normalized/validated themeConfig. If validation ensures that themeConfig.navbar is mandatory, we shouldn't have to deal with a partial theme config and handle undefined that can't happen in practice.

The main problem is that we have no way for the theme to declare its ThemeConfig param, we should have a generic like Plugin<PluginContent = unknown,PluginThemeConfig = unknown> and get the right ThemeConfig type injected in the method.

Not sure how easy this refactor would be, but we should add more generic types someday.

In the meantime I'll just add an adapter layer:

image

@slorber slorber merged commit bfd7fd9 into main Dec 3, 2021
@slorber slorber deleted the jc/eslint-improve branch December 3, 2021 16:38
@Josh-Cena Josh-Cena added pr: maintenance This PR does not produce any behavior differences to end users when upgrading. pr: polish This PR adds a very minor behavior improvement that users will enjoy. and removed status: awaiting review This PR is ready for review, will be merged after maintainers' approval pr: polish This PR adds a very minor behavior improvement that users will enjoy. pr: maintenance This PR does not produce any behavior differences to end users when upgrading. labels Dec 9, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
CLA Signed Signed Facebook CLA pr: polish This PR adds a very minor behavior improvement that users will enjoy.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants