-
Notifications
You must be signed in to change notification settings - Fork 122
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
test(xy): scale type improvements #1381
Conversation
6306ebf
to
a1b8a59
Compare
a1b8a59
to
bb93b5a
Compare
test this |
packages/charts/src/chart_types/xy_chart/annotations/line/dimensions.ts
Outdated
Show resolved
Hide resolved
packages/charts/src/chart_types/xy_chart/annotations/rect/dimensions.ts
Outdated
Show resolved
Hide resolved
packages/charts/src/chart_types/xy_chart/state/selectors/compute_annotations.ts
Outdated
Show resolved
Hide resolved
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 haven't gone too far, but in general this are the current assumptions for cartesian:
yScale
is always Scale<number>
xScale
is always Scale<number|string>
, can be restricted if required but most of the time I don't need to know if the value I'm sending to the scale is a number or a string, I just need to know that the output of the scale is a number
const padding = (xScale.step - (xScale as ScaleBand<string | number>).originalBandwidth) / 2; | ||
annotationValueXPosition -= padding; | ||
} else { | ||
annotationValueXPosition += xScale.originalBandwidth / 2; | ||
annotationValueXPosition += (xScale as ScaleBand<string | number>).originalBandwidth / 2; |
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 you can remove this assertion because isBandScale
already define xScale as ScaleBand
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, will check! I haven't added assertions where there was no complaint, but it's possible that a later commit made an earlier assertion unnecessary, indeed a good idea to revisit all
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.
Indeed, I only later turned the type guard function generic, now it no longer complains there 👯♀️
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.
const dimensions = computeRectAnnotationDimensions( | ||
annotationSpec, | ||
yScales, | ||
xScale as Scale<number>, |
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.
why you are restricting this to number
only if the passed one could be both?
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.
You can change computeRectAnnotationDimensions
to accept Scale<unknown>
because internally you are calling isBandScale
that assert the type for you
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.
Re the question, it's because it's in a conditional branch, and I didn't want to add potentially unduly restrictive types in the other, unrelated branch in the first round of 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.
I can't change computeRectAnnotationDimensions
to accept Scale<unknown>
because calling limitValueToDomainRange
will have a red squiggly mark (limitValueToDomainRange
performs a subtraction of domain values, so it must be numeric) and for the same reason it can't be Scale<number | string>
either
Basically the computeRectAnnotationDimensions
only seems to work with numeric X, though I haven't tested the runtime, it was enough for me to see the subtraction. Though the subtraction only happens if the domain length is non-zero, I assumed it's always the case
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.
By extension, the entire computeRectAnnotationDimensions
only works with a numeric X scale, Marco or Nick lmk if it's not the case
@@ -64,7 +64,7 @@ export function computeRectAnnotationDimensions( | |||
let xAndWidth: { x: number; width: number } | null = null; | |||
|
|||
if (isBandScale(xScale)) { | |||
xAndWidth = scaleXonBandScale(xScale, x0, x1); | |||
xAndWidth = scaleXonBandScale(xScale as ScaleBand<number>, x0, x1); |
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 also seems unnecessary, see my previous comment in file /xy_chart/annotations/utils.ts
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, thanks for the catch, I need to revisit these (the assertion was done before the function param types were tightened)
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.
@@ -31,8 +31,8 @@ import { | |||
export function renderArea( | |||
shift: number, | |||
dataSeries: DataSeries, | |||
xScale: Scale, | |||
yScale: Scale, | |||
xScale: Scale<number>, |
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 be string|number
as every other xScale
The scale is used in the pathGenerator.x
function with the data coming from dataSeries.data
where the x can be both string or number DataSeriesDatum.x
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.
xScale? are we ever linking ordinals with a line? I tightened it to number
because:
- it unconditionally calls
renderPoints
which expects numeric - I wasn't aware of using lines for ordinals
- tests let it pass
Just made a quick attempt to relax the xScale
param of renderPoints
to also allow strings and it didn't complain, so I can relax it here too, though no idea why I didn't get a complaint for my exclusion of the strings, will look into 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.
@@ -21,8 +21,8 @@ import { MarkSizeOptions } from './utils'; | |||
export function renderBubble( | |||
shift: number, | |||
dataSeries: DataSeries, | |||
xScale: Scale, | |||
yScale: Scale, | |||
xScale: Scale<number>, |
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.
number|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.
@@ -30,8 +30,8 @@ import { | |||
export function renderLine( | |||
shift: number, | |||
dataSeries: DataSeries, | |||
xScale: Scale, | |||
yScale: Scale, | |||
xScale: Scale<number>, |
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.
number|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.
@@ -29,8 +29,8 @@ import { | |||
export function renderPoints( | |||
shift: number, | |||
dataSeries: DataSeries, | |||
xScale: Scale, | |||
yScale: Scale, | |||
xScale: Scale<number>, |
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.
number|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.
Thanks Marco, will revisit these!
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.
const defaultDomain = domain.length === 0 ? [undefined] : domain; | ||
return new ScaleBand(defaultDomain, [0, maxRange], undefined, singlePanelSmallMultiple ? 0 : padding); | ||
return new ScaleBand( | ||
domain.length > 0 ? domain : [(undefined as unknown) as number], |
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 we've already been cheating to comply with the D3 scale typedef file and the D3 doc, but now we're clear about it. I'll try to solve it in a next PR, it's only partially addressed in this one
} | ||
return false; | ||
const nextLastDrag = nextProps.lastDrag; | ||
return nextLastDrag !== null && (prevLastDrag === null || prevLastDrag.end.time !== nextLastDrag.end.time); |
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.
Replacing a hairy control structure and making the logical conditions less redundant
🎉 This PR is included in version 37.0.0 🎉 The release is available on: Your semantic-release bot 📦🚀 |
Summary
As a first step for comprehensive type safety, this PR increases TS type safety to the central Cartesian functions/methods/classes and lots of utility and render function dependencies through turning the
Scale
generic on its domainDetails
There were a couple of strategically placed
any
s in theScale
interface, and elsewhere. Though low in number, their propagating effect meant that most of the xy code doesn't really enjoy type safety, there can always be a scale inducedany
leak, so only very specific functions could be considered type safe.The current PR is a start of work, focusing on
Scale.domain
,Scale.ticks
, and its positive effects onScale
methods and lots of other functions. While there's still a lot of dirt swept under the carpet (just grepas Scale<
) it's way more explicit, and these assertions can be solved one by one.So, statically a lot more places where we assert or say
any
, but it's more explicit, closer to the as yet unresolved bits.There's also a place where the D3 scale is called with a type that's not enabled (
[undefined]
domain); it's now marked explicitly.Issues
Under the umbrella of #1303
Checklist
:xy
,:partition
):interactions
,:axis
)closes #123
,fixes #123
)