-
Notifications
You must be signed in to change notification settings - Fork 31
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
Introduce RenderingTarget
type and CombinedProps
pattern
#7359
Conversation
'no-shadow': 'off', // We use the typescript-eslint version as eslint false positives on enums | ||
'@typescript-eslint/no-shadow': ['error'], |
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.
Without making this change, we'd getting a variable is already declared in upper scope
warning from ESLint, despite that not being the case. Using the typescript version of this rule fixes this problem
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 this needed even without the use of TypeScript enum
s?
@@ -125,10 +125,10 @@ export const FormField = ({ | |||
}, | |||
] | |||
.concat(formField.options) | |||
.map(({ value, label }) => { | |||
.map(({ value, label: formLabel }) => { |
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.
Fix a 'no shadow' error
const nextOffset = offsets | ||
.reverse() | ||
.find((offset) => offset < scrolled); | ||
const nextOffset = offsets.reverse().find((o) => o < scrolled); |
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.
Fix a 'no shadow' error
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.
Could also drop the reverse
with Array.prototype.findLast
if it’s polyfilled?
Just mentioning as reverse
modifies the array in place
Size Change: -1.02 kB (0%) Total Size: 515 kB
ℹ️ View Unchanged
|
⚡️ Lighthouse report for the changes in this PRReport for Article
|
⚡️ Lighthouse report for the changes in this PRReport for Front
|
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.
Nice! Very thorough documentation.
|
||
/** | ||
* This type can be set to either AppsProps or WebProps, and takes two generics | ||
* one for each rendering targets props |
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 know that we're not exporting this, but I think it would be useful to elaborate a bit on how this type works? (I think I know, but I'm not super confident on the details, and it feels like something that would be useful for future travellers.)
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 good to me! I've just added one small comment about documentation 🙂
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.
Looks good to me! I really appreciated the clear explanations
/** | ||
* An enum defining what where we are targeting a particular rendered | ||
* page to be shown | ||
* | ||
* This can be used to make decisions during rendering, where there | ||
* might be differences in the requirements of each target. | ||
* | ||
* Targets: | ||
* - Web => A full web browser, such as chrome or safari on a desktop computer, laptop or phone. | ||
* - Apps => A webview rendered within the Android or iOS live apps | ||
*/ | ||
export enum RenderingTarget { | ||
Web, | ||
Apps, | ||
} |
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 I mentioned in the RFC, I would recommend avoiding TypeScript enums, as they “are one of the few features TypeScript has which is not a type-level extension of JavaScript”1.
To prove my point, what do you expect the value of RenderingTarget[0]
to be? What about RenderingTarget.Web === 0
?
Footnotes
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.
Would your suggestion be to use a string union? What's the best alternative
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.
Yes, string unions are a lot less confusing. If you need to do custom type-guard, the pattern I shared in the RFC works well:
// If you define a array `as const`… const renderingTarget = [ "Web", "Apps", "Editions", ] as const; // … you can infer the type from it… export type RenderingTarget = renderingTarget[number]; // … and create a custom type guard, if you so desire! export isRenderingTarget = (target: string): target is RenderingTarget => renderingTarget.map(String).includes(target)
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 like it bring a lot if type safety and is well documented: great!
Should the no-shadow
change be extracted out of this PR?
Is the complexity of this wrapper type worth it compared to a naive implementation?
interface CommonProps {
value: string;
target: RenderingTarget; // enum or string union
}
interface AppProps extends CommonProps {
target: "Apps";
apiUrl: string;
}
interface WebProps extends CommonProps {
target: "Web";
}
const Component = (props: AppProps | WebProps) =>
<>{/* … */}</>
Based on the RFC #7174, this PR creates the
RenderingTarget
type andCombinedProps
pattern.DCR & AR are becoming one - specifically we are adding the capability for DCR to render articles for the app.
We will continue to use the Frontend model for both web & apps articles, and generally web and apps articles will be the same. However, there are some differences in requirements, mainly based on the technical impact of the target:
To support these differences, this PR introduces the idea of a
RenderingTarget
, an enum which allows a component or function to know whether the content being rendered will be shown either on the web or the apps.Additionally, to support differing requirements of data - a rare but nonetheless necessary occurrence - this PR introduces the
CombinedProps
type & pattern which allows the passing of 'web only' or 'apps only' props, ensuring our type safety is not diluted when rendering for different targets.Most of the additional details & reasoning are outlined in the RFC: #7174
An important part of this PR is the JSDoc documentation, so please provide feedback of the wording can be improved or better formatted!