admin-rte: Enable TypeScript strict mode - #6260
Conversation
|
Important Draft PR not reviewedDraft PRs are not automatically reviewed by default.
To automatically review draft PRs, update your CodeRabbit configuration: reviews:
auto_review:
drafts: trueComment |
| // Not typed as `FieldValidator<...>`: its optional `meta` parameter makes the type invariant in the field | ||
| // value, which keeps the validator from being used for a `string`-valued field. | ||
| export const requiredValidator = (value: string | RawDraftContentState | undefined): ReactNode => { |
There was a problem hiding this comment.
Is there a way to keep using the FinalForm typing? Keeping the final form types seems more correct
There was a problem hiding this comment.
You were right, and it is now a FieldValidator again — 207fee8.
FieldValidator is invariant in the field value: FieldState both accepts it (change: (value: FieldValue | undefined) => void) and returns it, so FieldValidator<string | RawDraftContentState | undefined> is not assignable to FieldValidator<string>, which is what createRteField needs. A single instantiation therefore cannot work — but a generic one can:
export const requiredValidator = <T extends string | RawDraftContentState | undefined>(
...[value]: Parameters<FieldValidator<T>>
): ReactNode => { ... };I verified the four candidates by compiling assignments rather than reasoning about it: the wide instantiation fails for FieldValidator<string>; an intersection of instantiations fails for a raw-state field; the generic satisfies both FieldValidator<string> and FieldValidator<RawDraftContentState>. It is also less restrictive than before for consumers, since it now fits either field value.
Generated by Claude Code
Strict mode is enabled in the starter, so the packages should follow. All four errors come from strictFunctionTypes, which compares callback parameters contravariantly: - ControlButton attaches onButtonClick to a button element, so the prop is typed with MouseEvent<HTMLButtonElement> instead of the wider MouseEvent<Element>. - useInlineStyleType annotated its click handler with the DOM's global MouseEvent rather than React's, so it did not match IFeatureConfig. - createComponentSlot drops the generic of MUI's Select, which types the slot's onChange with an unknown value. useBlockTypes follows and narrows the block type where it is read. - requiredValidator is no longer declared as FieldValidator: its optional meta parameter makes the type invariant in the field value, so the validator could not be passed to a string-valued Field.
95d86f8 to
eda0763
Compare
Keep requiredValidator a FieldValidator by making it generic over the field value, instead of dropping the final-form type. FieldValidator is invariant in the field value because FieldState both accepts and returns it, so a single wide instantiation could not be passed to a string-valued Field; a generic can. Explain in useBlockTypes why the Select slot's event cannot stay typed with DraftBlockType, and why the value has to be narrowed before use.
The reasoning belongs in the review conversation, not in the code.
Notes on the three non-obvious changesWhy the
|
| Form | FieldValidator<string> |
FieldValidator<RawDraftContentState> |
|---|---|---|
| single wide instantiation | ✗ | ✓ |
| intersection of instantiations | ✓ | ✗ |
| generic | ✓ | ✓ |
So the generic is the only form that keeps the final-form type and works for either field value — and it is less restrictive for consumers than what is on main today.
Generated by Claude Code
Status quo
Strict mode is not enabled everywhere in this repo.
packages/admin/tsconfig.base.jsonstops atnoImplicitAnyandstrictNullChecks, so@dextinity/admin-rteruns without the remaining strict checks.Change
Enable
strictfor the package. All four resulting errors come fromstrictFunctionTypes, which compares callback parameters contravariantly:ControlButtonattachesonButtonClickto abuttonelement, so the prop is typed with React'sMouseEventforHTMLButtonElementinstead of the wider one forElement.useInlineStyleTypeannotated its click handler with the DOM's globalMouseEventinstead of React's, so it did not matchIFeatureConfig.createComponentSlotdrops the generic of MUI'sSelect, which types the slot'sonChangewith anunknownvalue.useBlockTypesfollows and narrows the block type where it is read.requiredValidatoris no longer declared as aFieldValidator: its optionalmetaparameter makes the type invariant in the field value, so it could not be passed to astring-valuedField.Verification
Compared the emitted
.d.tsfiles againstmain. Three types change, none of them breaking: the two in the changeset sit in a contravariant position, so handlers and validators that type-checked before still do, andBlockChangeEventis not reachable through anything exported.@dextinity/admin,@dextinity/cms-admin, the demo admin and Storybook typecheck against the rebuilt package.Further information