Skip to content

Barrel re-exports DateTimePickerProps from the optional peer @mui/x-date-pickers, so the type is any for consumers who skip it #1749

Open

Description

@chellej

Current Behavior

dist/index.d.ts re-exports DateTimePickerProps from @mui/x-date-pickers/DateTimePicker:

import { DateTimePickerProps } from '@mui/x-date-pickers/DateTimePicker';
export { DateTimePickerProps } from '@mui/x-date-pickers/DateTimePicker';

@mui/x-date-pickers is declared optional under peerDependenciesMeta, so a consumer is
entitled to skip it. When they do, that reference does not resolve and the type quietly collapses:

  • skipLibCheck: false -> TS2307: Cannot find module '@mui/x-date-pickers/DateTimePicker',
    pointing at sistent's own .d.ts rather than at the package actually missing;
  • skipLibCheck: true (the common default) -> DateTimePickerProps silently becomes any.

Reproduced against a clean consumer with the optional peer absent - this probe compiles, which
it only can if the type degraded to any:

import type { DateTimePickerProps } from '@sistent/sistent';
type IsAny<T> = 0 extends (1 & T) ? true : false;
export const p: IsAny<DateTimePickerProps> = true;

Expected Behavior

Either the type does not appear in the barrel's public surface at all, or it resolves for every
consumer. A public type must not depend on a package the consumer was explicitly told is optional.

Context

This is the declaration-side twin of the optional-peer rule already documented in AGENTS.md
("The barrel must not require an optional peer"). The two fail in opposite directions: that one is
broken by a runtime import, this one by a type re-export - and import type being erased at
runtime is exactly why the existing runtime guard cannot see it.

DateTimePicker itself is correct here: it defers the runtime import via React.lazy
(src/base/DateTimePicker/DateTimePicker.tsx), which is the documented fix for the runtime half.
Only the type re-export is left over.

Discovered while fixing the same class of defect for @meshery/schemas, whose Key type was
degrading to any the same way. That fix landed with a guard,
src/__testing__/publishedTypeSurfaceDependencies.test.ts, which asserts that every external
package named by the built dist/index.d.ts is a real dependency or peerDependency.
@mui/x-date-pickers is currently exempted on the record in that guard's optional-peer
exemption list, pointing at this issue - so the guard stays honest about the hole instead of
hiding it.

Suggested fix

Preferred: stop re-exporting DateTimePickerProps from the root barrel, so the optional peer stops
being part of the published type surface.

Alternatives considered and not chosen:

Once resolved, delete the @mui/x-date-pickers entry from OPTIONAL_PEERS_ON_THE_RECORD in
src/__testing__/publishedTypeSurfaceDependencies.test.ts; the guard asserts each exemption is
still needed, so a stale entry fails the test rather than lingering.

Activity

  1. Valyrian-Code commented on Jul 26, 2026

    @Valyrian-Code

    @chellej I'd like to work on this one, could you assign it to me?

    One thing I hit while reproducing it: removing the export type { DateTimePickerProps } from src/base/DateTimePicker/index.tsx isn't enough on its own. I tried exactly that and rebuilt, and dist/index.d.ts still has

    import { DateTimePickerProps } from '@mui/x-date-pickers/DateTimePicker';

    because the exported component is itself declared with that type:

    declare const DateTimePicker: React.ForwardRefExoticComponent<
      DateTimePickerProps & React.RefAttributes<HTMLDivElement>
    >;

    so the import survives to serve that declaration. It goes 2 references -> 1, not 0, which means the @mui/x-date-pickers entry in OPTIONAL_PEERS_ON_THE_RECORD still can't be deleted (the guard asserts each exemption is still needed, so it'd have to stay).

    So the props type the component is declared with has to stop naming the peer too, not just the re-export. The way that keeps the public API intact, as far as I can tell, is a local props type in sistent for the wrapper's own surface, with the real MUI type used only inside the implementation where the declaration bundle doesn't emit it.

    Happy to go that way, but since it touches the public shape of DateTimePickerProps I'd rather check the direction with you before writing it. Is the local-type approach what you had in mind, or would you prefer the picker move behind its own entry point?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions