-
Notifications
You must be signed in to change notification settings - Fork 162
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
Tree component refactoring #1863
base: master
Are you sure you want to change the base?
Conversation
Using ReturnType on all sub-states except for controls (which already has a type to be used directly) and narrative (the compiler was not able to resolve types between return values and default state). The next commit will fix the narrative type.
9ecca22
to
8280aaa
Compare
8280aaa
to
33277b5
Compare
src/components/tree/tree.js
Outdated
} | ||
|
||
clearSelectedNode = () => { | ||
callbacks.clearSelectedNode.bind(this); |
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.
[reminder to me] - check this change, I remember binding callbacks in the constructor was "the right way" way back when I was writing this code.
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 see:
auspice/src/components/map/map.js
Lines 84 to 85 in 3cd0c1e
// https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-no-bind.md#es6-classes | |
this.fitMapBoundsToData = this.fitMapBoundsToData.bind(this); |
@genehack could you take a look at the types added / used here if you have a chance? 🙏 |
This was necessary to properly type the root state. Note: AnyAction is used for `action` which is only slightly better than any. Ideally, each action type would come with its own TypeScript interface but there is no good way to tightly couple those. I think the right improvement here is to use Redux's createSlice but that is beyond the scope of adding types.
This allows type checking on the new entries.
This does not provide much benefit as-is, but should facilitate future usage of TypeScript within the component.
The commented out usage was removed in "Excise react-svg-pan-zoom" (56fbb8a).
Keep consistent with other parts of the file.
Only the clearSelectedNode binding needs to be kept in the constructor.
6d65167
to
ceec881
Compare
src/components/tree/tree.js
Outdated
const anyTreeZoomed = this.props.tree.idxOfInViewRootNode !== 0 || | ||
this.props.treeToo.idxOfInViewRootNode !== 0; | ||
|
||
const activeResetTreeButton = anyTreeZoomed; |
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.
if you're gonna make these two variables the same thing why not just go the one extra step and rename treeIsZoomed
directly to activeResetTreeButton
, and then update the ternaries below to also use activeResetTreeButton
? Seems less confusing in the longer run.
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.
Good point, done: 4d8a2e0
I chose to go the other way around and drop activeResetTreeButton
in favor of anyTreeZoomed
to convey the condition rather than end state.
src/reducers/controls.ts
Outdated
interface Defaults { | ||
distanceMeasure: string | ||
layout: Layout | ||
geoResolution: string | ||
filters: Record<string, any> | ||
filtersInFooter: string[] | ||
colorBy: string | ||
selectedBranchLabel: string | ||
tipLabelKey: typeof strainSymbol | ||
showTransmissionLines: boolean | ||
sidebarOpen?: boolean | ||
} |
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'd put this up around L15, so it's defined before being used in the (current) L18 -- was briefly confused where Defaults
was even coming from.
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:
auspice/src/reducers/controls.ts
Lines 15 to 32 in 4658803
type Layout = "rect" | "radial" | "unrooted" | "clock" | "scatter" | |
interface Defaults { | |
distanceMeasure: string | |
layout: Layout | |
geoResolution: string | |
filters: Record<string, any> | |
filtersInFooter: string[] | |
colorBy: string | |
selectedBranchLabel: string | |
tipLabelKey: typeof strainSymbol | |
showTransmissionLines: boolean | |
sidebarOpen?: boolean | |
} | |
export interface BasicControlsState { | |
defaults: Defaults | |
layout: Layout |
src/reducers/controls.ts
Outdated
filtersInFooter: string[] | ||
colorBy: string | ||
selectedBranchLabel: string | ||
tipLabelKey: typeof strainSymbol |
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.
what's the advantage of doing this versus adding a proper type in ../utils/globals
and exporting it from 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.
I didn't want to dig a deeper hole and convert src/utils/globals.js
to TypeScript. Even if I were to do that, I'm not sure that adding a proper type would be useful in this case. In globals.ts
it would simply be:
- export const strainSymbol = Symbol('strain');
+ export const strainSymbol: unique symbol = Symbol('strain');
and the same typeof strainSymbol
would still be used here.
state: NarrativeState = defaultState, | ||
action: AnyAction, |
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.
can you provide a default value to a positional param if there's a subsequent positional param without a default value? or do you need to switch the order here, or convert this to being passed an object?
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.
Good point – ESLint and TypeScript clearly had no complaints about this so I searched to confirm – it is allowed in JavaScript. From MDN docs on default parameters:
Parameters are still set left-to-right, overwriting default parameters even if there are later parameters without defaults.
function f(x = 1, y) { return [x, y]; } f(); // [1, undefined] f(2); // [2, undefined]
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 it's a good pattern, but it is the pattern used for other files in src/reducers/
so I will keep it as-is.
- `treeIsZoomed` is ambiguous since the condition considers two trees. Rename to `anyTreeZoomed`. - `activeResetTreeButton` has the same condition as `anyTreeZoomed`. Reuse the existing variable.
Partial<ControlsState> previously worked but has the side effect of marking all keys as optional, which is not accurate and prone to cause future type errors.
ceec881
to
4658803
Compare
Description of proposed changes
Changes made while prepping for #1373. These can be considered independently from that PR. See individual commit messages.
Checklist
If making user-facing changes, add a message in CHANGELOG.md summarizing the changes in this PRno functional changes(to be done by a Nextstrain team member) Create preview PRs on downstream repositories.no functional changes