Conversation
# Conflicts: # static/app/views/dashboards/widgetBuilder/components/sortBySelectors.tsx
# Conflicts: # static/app/components/teamSelector.spec.tsx # static/app/utils/convertFromSelect2Choices.tsx
| /** | ||
| * Unlike react-select which expects an OptionType as its value | ||
| * we accept the option.value and resolve the option object. | ||
| * Because this type is embedded in the OptionType generic we | ||
| * can't have a good type here. | ||
| */ | ||
| value?: any; |
There was a problem hiding this comment.
I’ll tackle this in a follow-up
| // todo(tkdodo): typing `p` and keeping `any` localized avoids leaking it | ||
| const props = p as any; |
There was a problem hiding this comment.
at least this confines the blast radius of any to the inside of this component. It’s an even bigger mess to clean up internally, and I doubt we’ll see it happen. I’d rather throw the select away and do a new one.
| export type { | ||
| Props, | ||
| NamedProps, | ||
| NamedProps as Props, |
There was a problem hiding this comment.
building on top of NamedProps instead of Props is what enables the type-safety, because for some reason, Props is just NamedProps intersected with:
export type SelectComponentsProps = { [key in string]: any };
🤷♂️
| }} | ||
| options={mapToOptions(emails)} | ||
| onBlur={(e: React.ChangeEvent<HTMLInputElement>) => { | ||
| onBlur={(e: any) => { |
There was a problem hiding this comment.
event is a FocusEvent but somehow we expect a ChangeEvent here 🤷
| isInsideModal | ||
| /> | ||
| <TeamSelector | ||
| organization={organization} |
There was a problem hiding this comment.
TeamSelector doesn’t accept organization as a prop - it calls useOrganization() internally.
| onChange={({value}: any) => onComparisonDeltaChange(value)} | ||
| onChange={({value}) => onComparisonDeltaChange(value)} | ||
| options={comparisonDeltaOptions} | ||
| required={comparisonType === AlertRuleComparisonType.CHANGE} |
There was a problem hiding this comment.
required does nothing (I checked)
| options={Object.keys(sortDirections).map(value => ({ | ||
| // @ts-expect-error TS(7053): Element implicitly has an 'any' type because expre... Remove this comment to see the full error message | ||
| label: sortDirections[value], | ||
| value, | ||
| options={Object.entries(sortDirections).map(([value, label]) => ({ | ||
| value: value as SortDirection, | ||
| label, |
There was a problem hiding this comment.
using Object.entries over Object.keys to avoid the indexed access. value is still a string here so it needs a type assertion.
| > | ||
| <Select | ||
| required | ||
| options={METRIC_CHOICES.slice()} |
There was a problem hiding this comment.
not sure why we made a shallow copy of an object here? I sure don’t hope that the component mutates them, but I’ve inlined nonetheless
| options={repositories} | ||
| noOptionsMessage={() => t('No repositories found')} | ||
| menuPortalTarget={document.body} | ||
| prefix={<IconRepository size="sm" />} |
There was a problem hiding this comment.
There is no prefix on Select. Maybe this used to be a compactSelect at some point?
| value={selectedTemplate} | ||
| options={menuOptions} | ||
| disabled={disabled} | ||
| disabledReason={disabledReason} |
There was a problem hiding this comment.
another form field level prop, not on Select
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 2 potential issues.
Bugbot Autofix prepared fixes for both issues found in the latest run.
- ✅ Fixed: New
onChangetype omitsnullfor clearable selects- Updated SingleProps.onChange type to accept
OptionType | nullto handle react-select passing null when clearable selects are cleared.
- Updated SingleProps.onChange type to accept
- ✅ Fixed:
AsyncPropsreintroduces explicitly omitted props inControlProps- Applied Omit to AsyncProps and CreatableProps to prevent reintroduction of onChange, value, menuPlacement, and theme props that were explicitly excluded.
Or push these changes by commenting:
@cursor push a33eba44ab
Preview (a33eba44ab)
diff --git a/static/app/components/core/select/select.tsx b/static/app/components/core/select/select.tsx
--- a/static/app/components/core/select/select.tsx
+++ b/static/app/components/core/select/select.tsx
@@ -409,7 +409,7 @@
type SingleProps<OptionType extends OptionTypeBase> = {
multiple?: false;
- onChange?: (option: OptionType) => void;
+ onChange?: (option: OptionType | null) => void;
};
type SelectProps<OptionType extends OptionTypeBase> =
@@ -418,8 +418,8 @@
export type ControlProps<OptionType extends OptionTypeBase = GeneralSelectValue> =
SelectProps<OptionType> &
- AsyncProps<OptionType> &
- CreatableProps<OptionType, boolean> &
+ Omit<AsyncProps<OptionType>, 'onChange' | 'value' | 'menuPlacement' | 'theme'> &
+ Omit<CreatableProps<OptionType, boolean>, 'onChange' | 'value' | 'menuPlacement' | 'theme'> &
Omit<
ReactSelectProps<OptionType, boolean>,
'onChange' | 'value' | 'menuPlacement' | 'theme'This Bugbot Autofix run was free. To enable autofix for future PRs, go to the Cursor dashboard.
The Select component typings were somehow flawed and turn every prop into `any`, making quite a mess on each call-side because not a single prop on select was properly type-checked. This PR fixes the select type issues, and in turn revealed over 100 issues on usages. I’ve tried to keep most changes type-only, and I’ll note where we have runtime specific changes in comments. Most runtime specific changes are about _removing_ props passed to `Select` that don’t exist and therefore don’t do anything. In many cases, we passed props that are usually passed to a `FormField` directly to Select. For some things I’ve just fallen back to `as any` to not affect anything, which is an okay trade-off because this PR will make all future usages of `Select` properly typed.


The Select component typings were somehow flawed and turn every prop into
any, making quite a mess on each call-side because not a single prop on select was properly type-checked.This PR fixes the select type issues, and in turn revealed over 100 issues on usages. I’ve tried to keep most changes type-only, and I’ll note where we have runtime specific changes in comments.
Most runtime specific changes are about removing props passed to
Selectthat don’t exist and therefore don’t do anything. In many cases, we passed props that are usually passed to aFormFielddirectly to Select.For some things I’ve just fallen back to
as anyto not affect anything, which is an okay trade-off because this PR will make all future usages ofSelectproperly typed.