juspay / juspay/rescript-bindgen
Catalog of `minor` fidelity widenings (TS type vs generated ReScript) for triage — blend 0.0.37-beta.6
- Dominant language
- ReScript
- Stars
- 8
- Forks
- 0
- Avg merge
- 9h 33m
- Merged PRs (30d)
- 15
Description
## Detailed catalog of `minor` fidelity findings — generated bindings vs blend `0.0.37-beta.6`
Re-validation came back **0 confirmed majors** (see #63). This issue lists every **`minor`** finding (69 across 36 components) with its **TS type vs generated ReScript type**, for triage. None is a compile error (build is green) — each is a widening or representation choice. Filed so the team can decide which deserve tighter typing.
Generator: `pkg.pr.new@62`.
### 🔎 Worth a closer look (the only ones that lose guarantees, not just precision)
- **Discriminated-union flattening** — `Card` (`variant`/`alignment`/`children`), `SelectItemV2` (`selected`/`selectedValues`), `Badge` (`StandaloneBadgeProps | PositionedBadgeProps`): all props present & correctly typed, but emitted **all-optional**, so per-branch required-ness is lost. Candidate for a real enhancement (e.g. a ReScript variant per branch).
- Everything else is an inherent TS→ReScript gap (CSS/styled-components/generics → `string`), a convention (`| null`→optional, `ReactNode`→`React.element`, `number`→`int`/`float`), or a documented opaque/overload mapping — all already carry `⚪ loose`/`ⓘ` comments.
### Full list
| Component | Prop | TS type | Generated ReScript | Why minor |
|---|---|---|---|---|
| `AvatarGroup` | `avatars[].fallback` | `string \| React.ReactNode` | `React.element` | AvatarData.fallback is `string \| React.ReactNode` in TS; binding (AvatarGroupTypes.avatarData.fallback) maps it to React.element only, dr… |
| `AvatarV2` | `onImageError` | `(error: Error) => void` | `JsError.t => unit` | TS (error: Error) => void mapped to JsError.t => unit — faithful arity/return. No defect. |
| `AvatarV2` | `width / height` | `CSSObject['width']` | `string` | TS AvatarV2Dimensions uses CSSObject['width']/['height'] (Property.Width \| number \| undefined). Binding widens to string. Acceptable sty… |
| `Badge` | `BadgeProps union` | `StandaloneBadgeProps \| PositionedBadgeProps` | `single flattened props` | TS BadgeProps is a discriminated union (StandaloneBadgeProps with children:undefined \| PositionedBadgeProps with required children/positi… |
| `Badge` | `offset` | `[number, number]` | `string` | TS PositionedBadgeProps.offset is `[number, number]` tuple; binding maps to string with an explicit `// ⚪ loose` comment. Documented limit… |
| `Button` | `(spread) HTML attributes` | `& Omit, 'style' \| 'className'>` | `...HtmlAttrs.buttonHTMLAttributesOmitClassNameDisabledOnClickStyle` | Binding additionally omits disabled and onClick from the spread because they are explicitly declared as own props; this is correct de-dupl… |
| `Button` | `justifyContent` | `CSSObject['justifyContent'] (styled-components CSS union)` | `justifyContent?: string` | styled-components CSS property union widened to string. Known-acceptable widening of a styled-components type. |
| `Button` | `onClick` | `onClick?: (event?: React.MouseEvent) => void (a SINGLE optional-arg signature)` | `onClick?: ButtonTypes.OnClick.t (opaque) with comment '// was overloaded function (2 call signatures)'` | The TS source has exactly one call signature, not two; the bindgen comment claiming '2 call signatures / overloaded' is inaccurate for thi… |
| `Card` | `variant / alignment / children` | `CardProps = {maxWidth?,maxHeight?,minHeight?,skeleton?} & (DefaultCardProps \| AlignedCardProps \| CustomCardProps); discriminated union where alignment is required in AlignedCardProps, children required in CustomCardProps, and variant is the discriminant (required in Aligned/Custom).` | `all flattened into one make signature with every prop optional: ~variant=?, ~alignment=?, ~children=?, etc.` | The discriminated union of the three card shapes is flattened into a single all-optional argument list. This loosens optionality (e.g. Ali… |
| `CodeEditorV2` | `onBlur` | `onBlur?: () => void` | `onBlur?: EditorSharedTypes.OnBlur.t (opaque, with asThunk/asEvent helpers)` | TS CodeEditorV2Props declares onBlur as a plain `() => void`, but the intersected Omit void` | `onFocus?: EditorSharedTypes.OnFocus.t (opaque, with asThunk/asEvent helpers)` | Same overloaded-function widening as onBlur (HTMLAttributes onFocus not omitted in the Omit). Documented with `ⓘ` comment and OnFocus.asTh… |
| `CoreChart` | `data / hoveredKey / onHoveredKeyChange` | `NewNestedDataPoint[] \| null` | `Nullable.t>=?` | TS `NewNestedDataPoint[] \| null` and `string \| null` modeled as Nullable.t<...> — faithful (null preserved). `colors: {key;color}[]` -> … |
| `DataTable` | `columnManagerAlwaysSelected` | `(keyof T)[]` | `string` | TS is `(keyof T)[]` (an array); binding widens to a plain `string` (not array) with `// ⚪ loose — was (keyof T)[]`. The array-ness… |
| `DataTable` | `columns` | `ColumnDefinition[]` | `string` | `ColumnDefinition[]` widened to string with a `// ⚪ loose` comment — documented generic limitation (known-acceptable). |
| `DataTable` | `data / columns / idField` | — | — | Required props correctly emitted without =?. data:T[]->array<'a>, onRowSave/onRowClick/isRowLoading/getRowStyle arities and returns correc… |
| `DataTable` | `idField` | `keyof T` | `string` | `keyof T` widened to string with `// ⚪ loose` — documented (known-acceptable). |
| `DataTable` | `onColumnReorder / onFieldChange / onHeaderChange / onOperations / onInsertLeft / onInsertRight / onDeleteColumn` | `(ColumnDefinition[]) => void / (keyof T) => void` | `'b => unit (with ⓘ comment)` | Callbacks whose param is `ColumnDefinition[]` or `keyof T` are emitted as bare type variables ('b, 'c, 'd, 'e, 'f, 't6, 't7) with an ex… |
| `DateRangePicker` | `customPresets` | `PresetsConfig` | `string` | `PresetsConfig` (union array of DateRangePreset\|CustomPresetConfig\|CustomPresetDefinition) widened to string with `// ⚪ loose — was Pres… |
| `Drawer` | `activeSnapPoint / onSnapPointChange` | `number \| string \| null` | `CommonTypes.stringOrNumber=?` | TS `number \| string \| null` modeled as CommonTypes.stringOrNumber (the `null` member is dropped). Cosmetic union narrowing; the number\|… |
| `DrawerPortal` | `container` | `HTMLElement \| DocumentFragment \| null` | `~container: Dom.element=?` | vaul Portal container TS type is HTMLElement \| DocumentFragment \| null; binding widens to non-nullable Dom.element and carries an explic… |
| `DrawerV2` | `activeSnapPoint` | `number \| string \| null` | `CommonTypes.stringOrNumber=?` | TS number \| string \| null; binding uses non-nullable CommonTypes.stringOrNumber. null not representable, but prop is optional. Minor. |
| `DrawerV2` | `container` | `HTMLElement \| null` | `Nullable.t=?` | TS HTMLElement \| null correctly mapped to Nullable.t=?. Faithful. |
| `DrawerV2` | `onDrag/onRelease` | `(event: React.PointerEvent, n: number\|open: boolean) => void` | `('a, float) => unit / ('b, bool) => unit` | PointerEvent first arg could not be modelled; received as type variable ('a/'b) with explicit ⓘ comment. Second args (floa… |
| `DrawerV2` | `setActiveSnapPoint` | `(snapPoint: number \| string \| null) => void` | `CommonTypes.stringOrNumber => unit=?` | TS is (snapPoint: number \| string \| null) => void; binding types arg as CommonTypes.stringOrNumber (string\|float) dropping the null bra… |
| `DrawerV2NestedRoot` | `activeSnapPoint` | — | — | TS: number \| string \| null. Bound as CommonTypes.stringOrNumber (optional). The explicit `null` member is dropped (undefined handled by … |
| `DrawerV2NestedRoot` | `onDrag` | — | — | TS: (event: React.PointerEvent, percentageDragged: number) => void. Bound as ('a, float) => unit with a documented `ⓘ para… |
| `DrawerV2NestedRoot` | `onRelease` | — | — | TS: (event: React.PointerEvent, open: boolean) => void. Bound as ('b, bool) => unit with the documented type-variable comm… |
| `DrawerV2NestedRoot` | `setActiveSnapPoint` | — | — | TS: (snapPoint: number \| string \| null) => void. Bound as CommonTypes.stringOrNumber => unit; null member dropped. Minor. |
| `DrawerV2NestedRoot` | `snapPoints / fadeFromIndex` | — | — | DialogProps is intersected with (WithFadeFromProps \| WithoutFadeFromProps). Binding flattens both into optional snapPoints: array` | `record spreading JsxDOM.domProps` | TS is Omit,'className'\|'style'>. Binding maps to ReactTypes.reactPrimaryActionButtonPropsCo… |
| `MenuV2Content` | `onInteractOutside` | `(e: unknown) => void` | `JSON.t => unit` | TS (e: unknown) => void mapped to JSON.t => unit (same for onPointerDownOutside). Reasonable representation of an opaque event arg. alignm… |
| `PivotTableModal` | `columns` | `ColumnDefinition[]` | `string // ⚪ loose` | TS `ColumnDefinition[]` widened to `string` with documented `// ⚪ loose` comment. Known-acceptable generic limitation. |
| `PivotTableModal` | `data` | `T[]` | `array<'a>` | TS `T[]` (T extends Record) mapped to `array<'a>`. Reasonable generic handling. |
| `PivotTableModal` | `onConfigChange/onExport` | `(config: PivotTableConfig) => void` | `DataTableTypes.dataTableOnConfigChangeConfig => unit` | TS `(config: PivotTableConfig) => void` mapped to DataTableTypes.dataTableOnConfigChangeConfig => unit. Generic config approximated by … |
| `ResponsiveText` | `as` | `React.ElementType` | `ReactTypes.ElementType.t` | TS React.ElementType mapped to ReactTypes.ElementType.t (opaque) with an inline doc comment explaining construction helpers. Faithful/know… |
| `ResponsiveText` | `fontSize / color / fontWeight` | `CSSObject['fontSize'] \| CSSObject['color'] \| CSSObject['fontWeight']` | `string` | TS types are CSSObject['fontSize'] / CSSObject['color'] / CSSObject['fontWeight'] (styled-components indexed access). Binding widens all t… |
| `SelectItemV2` | `itemTokens` | `CSSObject['paddingTop'] etc. (string \| number \| undefined union)` | `string` | SelectV2MenuItemTokensBase CSSObject-valued fields (paddingTop, margin, borderRadius, fontSize, fontWeight, color, backgroundColor, etc.) … |
| `SelectItemV2` | `selected / selectedValues` | `selected: string (required when mode='single'); selectedValues: string[] (required when mode='multi')` | `~selected: string=?, ~selectedValues: array=?` | TS SelectItemV2Props is a discriminated union (SingleSelectItemV2Props \| MultiSelectItemV2Props). In the single branch `selected: string`… |
| `SingleSelect` | `items[].tooltip` | `string \| React.ReactNode` | `React.element` | SelectMenuItemType.tooltip is `string \| React.ReactNode`; binding maps tooltip to React.element. Since string is a valid ReactNode this i… |
| `SingleSelectV2Menu` | `collisionBoundary` | `Element \| Element[] \| null` | `ChatInputTypes.CollisonBoundaryRef.t` | TS type is DropdownMenuContentProps['collisionBoundary'] (Element \| Element[] \| null). Widened to an opaque ChatInputTypes.CollisonBound… |
| `StatCardV2NoData` | `filteredProps` | `React.ComponentProps<'div'> (DetailedHTMLProps, HTMLDivElement>)` | `string` | Widened to `string` with a documented `// ⚪ loose` comment. TS type is `React.ComponentProps<'div'>`. Known-acceptable documented limitati… |
| `StyledCheckboxIndicator` | `as_` | `as?: AsTarget (optional)` | `~as_: string (required)` | TS `as` (AsTarget) is optional but binding marks ~as_ as required (no =?). Cosmetic optionality mismatch on a loose-widened prop. |
| `StyledCheckboxIndicator` | `theme/as_/forwardedAs/style + return` | `FastOmit> union` | `string` | styled-components IStyledComponentBase, ...>>> widened to stri… |
| `StyledCheckboxRoot` | `as_` | `as?: AsTarget (optional)` | `~as_: string (required)` | TS `as` (AsTarget) optional but binding marks ~as_ as required (no =?). |
| `StyledCheckboxRoot` | `theme/as_/forwardedAs/style + return` | `FastOmit> union` | `string` | styled-components IStyledComponentBase, ...>>> widened to string with… |
| `StyledRadioV2Root` | `as_` | `as?: AsTarget (optional)` | `~as_: string (required)` | TS `as` (AsTarget) optional but binding marks ~as_ as required (no =?). |
| `StyledRadioV2Root` | `theme/as_/forwardedAs/style + return` | `Substitute> union` | `string` | styled-components IStyledComponentBase>, ...>> widened to string with '… |
| `StyledTabsContent` | `as_` | `as?: AsTarget (optional)` | `~as_: string (required)` | TS `as` (AsTarget) optional but binding marks ~as_ as required (no =?). |
| `StyledTabsContent` | `theme/as_/forwardedAs/style + return` | `Substitute> union` | `string` | styled-components IStyledComponentBase, ...>> widened to string with '// ⚪ loo… |
| `StyledTabsList` | `as_` | `as?: AsTarget (optional)` | `~as_: string (required)` | TS `as` (AsTarget) optional but binding marks ~as_ as required (no =?). |
| `StyledTabsList` | `theme/as_/forwardedAs/style + return` | `Substitute> union` | `string` | styled-components IStyledComponentBase, ...>> widened to string with '// ⚪ loose'… |
| `StyledTabsRoot` | `as_` | `as?: AsTarget (optional)` | `~as_: string (required)` | TS `as` (AsTarget) optional but binding marks ~as_ as required (no =?). |
| `StyledTabsRoot` | `theme/as_/forwardedAs/style + return` | `FastOmit> union` | `string` | Bound to exported StyledTabs (TabsProps & RefAttributes) — IStyledComponentBase widened to string with '// ⚪ loose' commen… |
| `StyledTabsTrigger` | `as_` | `as?: AsTarget (optional)` | `~as_: string (required)` | TS `as` (AsTarget) optional but binding marks ~as_ as required (no =?). |
| `StyledTabsTrigger` | `theme/as_/forwardedAs/style + return` | `Substitute> union` | `string` | styled-components IStyledComponentBase, ...>> widened to string with '// ⚪ … |
| `TabsContent` | `forceMount` | `forceMount?: true (literal)` | `~forceMount: bool=?` | TS Radix TabsContentProps types forceMount as the literal `true` (forceMount?: true); binding widens it to bool. Cosmetic widening; the on… |
| `TabsV2Content` | `forceMount` | `forceMount?: true` | `~forceMount: bool=?` | TS type is the literal `true` (forceMount?: true); binding widens to bool=?. Harmless widening of a single-literal flag. |
| `TabsV2Content` | `value` | `value: string (required)` | `~value: string` | Radix TabsContentProps.value is required (value: string); binding correctly marks ~value: string as required. Correct. |
| `TabsV2IconContainer` | `as_` | `as?: AsTarget` | `~as_: string (required)` | ~as_ is emitted as required (no =?), but styled-components `as` is optional. Minor optionality cosmetic on a loose-widened prop. |
| `TabsV2IconContainer` | `theme/as/forwardedAs/style` | `DefaultTheme \| styled-component union` | `string (loose)` | Styled-components span. theme/as/forwardedAs/style and return widened to string with documented `// ⚪ loose` comments — known-acceptable f… |
| `Tag` | `BlockProps style props` | `BlockProps` | `flattened block style props` | Tag extends Omit; the many flattened style props (CSSObject string values, stringOrNumber for padding/margin) are r… |
| `Tag` | `color` | `TagColor enum` | `~color: SplitTagTypes.color2=?` | TS color?: TagColor (neutral\|primary\|success\|error\|warning\|purple). Binding uses SplitTagTypes.color2 which is a polyvariant with tho… |
| `Tag` | `size` | `TagSize enum` | `~size: TagsTypes.size2=?` | TS size?: TagSize (xs\|sm\|md\|lg). Binding uses TagsTypes.size2 = xs\|sm\|md\|lg — exact members match; alias-name duplication only. |
| `Tag` | `text` | `text: string (required)` | `~text: string` | Required prop text: string correctly emitted as ~text: string (non-optional). Correct. |
| `Tag` | `variant/shape/leftSlot/rightSlot/splitTagPosition/showSkeleton/skeletonVariant` | `TagProps extras` | `faithful` | All present & correct: variant->tagVariant(noFill\|attentive\|subtle), shape->tagShape(rounded\|squarical), splitTagPosition->left\|right,… |
| `TextArea` | `wrap` | `CSSObject['whiteSpace']` | `string` | TS type is CSSObject['whiteSpace'] (a styled-components CSS union); widened to plain `string` in the binding. This is a reasonable/accepta… |
| `TextInputV2` | `dropdown` | `TextInputV2Dropdown \| TextInputV2Dropdown[]` | `string` | TS type is `TextInputV2Dropdown \| TextInputV2Dropdown[]` (SingleSelectV2Props & {position}). Widened to `string` placeholder, but carries… |
| `ThemeProvider` | `foundationTokens` | `ThemeType` | `'a` | TS type is ThemeType but the binding uses a free type variable `'a` instead of a concrete record/type. This is a widening (accepts anythin… |
| `UnitInput` | `value` | `number \| undefined (required key)` | `value: float (required)` | TS type is `number \| undefined` on a non-optional key. Binding maps to required `value: float`, dropping the `undefined` value possibilit… |
Contributor guide
No contributing guide indexed for this repository
Assessment
This issue has not been assessed yet.