Component
Breadcrumb
Package version
@fluentui/react-breadcrumb 9.4.5 (repo master; also reproduces against the version
@fluentui/react-components depends on).
React version
18.3.1
Environment
node v22.12.0, TypeScript as pinned by the repo root
@fluentui/react-breadcrumb 9.4.5
@fluentui/react-headless-components-preview 0.2.5
Current Behavior
packages/react-components/react-breadcrumb/library/src/components/BreadcrumbButton/BreadcrumbButton.types.ts:28
declares:
export type BreadcrumbButtonBaseProps = Omit<BreadcrumbButtonProps, 'size'>;
BreadcrumbButtonProps includes ComponentProps<ButtonSlots>, whose root is
ARIAButtonSlotProps — a distributive union over as: 'button' | 'a'. A plain Omit is not
distributive: it collapses the union into a single object type keyed on the intersection of its
members, and the anchor arm's href disappears from the resulting type.
The consequence is that the anchor spelling of BreadcrumbButton — the spelling the component's own
Default story uses — does not type-check against the base props type.
This is type-level only. Runtime rendering is unaffected.
Expected Behavior
BreadcrumbButtonBaseProps should preserve the distributive union, so that both arms
(as="button" and as="a" with href) remain assignable. @fluentui/react-button already does
exactly this for the same reason — Button.types.ts:72,84 use DistributiveOmit.
Reproduction
Minimal, in any TypeScript file in a workspace with @fluentui/react-breadcrumb installed:
import type { BreadcrumbButtonBaseProps } from '@fluentui/react-breadcrumb';
// Errors today: `href` does not exist on the collapsed type.
const props: BreadcrumbButtonBaseProps = { as: 'a', href: '/somewhere' };
A branch demonstrating the failure and the fix is available; happy to add a StackBlitz if the
triage flow needs one, though the failure is a compiler error rather than a runtime one and the
snippet above is sufficient to see it.
Steps to reproduce
- Add the snippet above to a
.ts file in a project that depends on @fluentui/react-breadcrumb.
- Run
tsc --noEmit.
- Observe the assignment error on
href.
Discovery context
Found during pixel-level verification of a styling layer built over
@fluentui/react-headless-components-preview. That work rebuilds each component's public prop
surface against its @fluentui/react-components twin and compiles the twin's own stories against
both, which is what surfaced this: the Breadcrumb Default story's anchor spelling would not compile
against the base props type.
Worth recording so this issue is not read as broader than it is: two further losses were originally
attributed to the same Omit (iconPosition, and a { href }-only object literal). Both were
re-measured and withdrawn — they fail against the Griffel surface too, for an unrelated reason
(TypeScript weak-type detection). Only the union collapse described above is a defect.
Proposed fix
Change the Omit to DistributiveOmit, matching @fluentui/react-button:
export type BreadcrumbButtonBaseProps = DistributiveOmit<BreadcrumbButtonProps, 'size'>;
One line, plus the regenerated etc/react-breadcrumb.api.md. No runtime change, and the widened
type is strictly a superset of the current one, so no existing consumer's code stops compiling.
A working implementation is included in PR #[WINDMOD-PR-NUMBER] (commit b95a4152c4); happy to
split it into a standalone PR against this issue if that is easier to take.
Suggested severity
Low - Has or doesn't need a workaround (the workaround is casting, which is exactly what a consumer
should not have to do).
Are you willing to submit a PR to fix?
yes
Component
Breadcrumb
Package version
@fluentui/react-breadcrumb9.4.5 (repomaster; also reproduces against the version@fluentui/react-componentsdepends on).React version
18.3.1
Environment
Current Behavior
packages/react-components/react-breadcrumb/library/src/components/BreadcrumbButton/BreadcrumbButton.types.ts:28declares:
BreadcrumbButtonPropsincludesComponentProps<ButtonSlots>, whoserootisARIAButtonSlotProps— a distributive union overas: 'button' | 'a'. A plainOmitis notdistributive: it collapses the union into a single object type keyed on the intersection of its
members, and the anchor arm's
hrefdisappears from the resulting type.The consequence is that the anchor spelling of
BreadcrumbButton— the spelling the component's ownDefault story uses — does not type-check against the base props type.
This is type-level only. Runtime rendering is unaffected.
Expected Behavior
BreadcrumbButtonBasePropsshould preserve the distributive union, so that both arms(
as="button"andas="a"withhref) remain assignable.@fluentui/react-buttonalready doesexactly this for the same reason —
Button.types.ts:72,84useDistributiveOmit.Reproduction
Minimal, in any TypeScript file in a workspace with
@fluentui/react-breadcrumbinstalled:A branch demonstrating the failure and the fix is available; happy to add a StackBlitz if the
triage flow needs one, though the failure is a compiler error rather than a runtime one and the
snippet above is sufficient to see it.
Steps to reproduce
.tsfile in a project that depends on@fluentui/react-breadcrumb.tsc --noEmit.href.Discovery context
Found during pixel-level verification of a styling layer built over
@fluentui/react-headless-components-preview. That work rebuilds each component's public propsurface against its
@fluentui/react-componentstwin and compiles the twin's own stories againstboth, which is what surfaced this: the Breadcrumb Default story's anchor spelling would not compile
against the base props type.
Worth recording so this issue is not read as broader than it is: two further losses were originally
attributed to the same
Omit(iconPosition, and a{ href }-only object literal). Both werere-measured and withdrawn — they fail against the Griffel surface too, for an unrelated reason
(TypeScript weak-type detection). Only the union collapse described above is a defect.
Proposed fix
Change the
OmittoDistributiveOmit, matching@fluentui/react-button:One line, plus the regenerated
etc/react-breadcrumb.api.md. No runtime change, and the widenedtype is strictly a superset of the current one, so no existing consumer's code stops compiling.
A working implementation is included in PR #[WINDMOD-PR-NUMBER] (commit
b95a4152c4); happy tosplit it into a standalone PR against this issue if that is easier to take.
Suggested severity
Low - Has or doesn't need a workaround (the workaround is casting, which is exactly what a consumer
should not have to do).
Are you willing to submit a PR to fix?
yes