From 1e7381efcf8e98b8dbc91fc5b837f8215b26458f Mon Sep 17 00:00:00 2001 From: web-padawan Date: Fri, 24 Jul 2026 12:43:19 +0300 Subject: [PATCH] fix!: resolve SelectItem barrel export collision in favor of the component The barrel exported the name SelectItem twice via star exports: the new SelectItem React component and the deprecated SelectItem type re-exported from @vaadin/select (deprecated in favor of SelectItemData in vaadin/web-components#12132). TypeScript resolved the duplicate to the first star export, breaking `SelectItem` in type positions (TS2749) and leaving resolution dependent on barrel line order. The generated barrel now emits explicit component re-exports after the star exports, so each component name deterministically resolves to the component. Adds a tsc-based regression fixture (test/typings/SelectItem.tsx) that compiles against the built @vaadin/react-components barrel and would have caught this: SelectItem in value/JSX position, SelectItemData in type position, and a @ts-expect-error asserting the deprecated type is no longer importable from the barrel root. BREAKING CHANGE: the deprecated TypeScript type SelectItem is no longer exported from the package barrel; use SelectItemData instead, or import the deprecated type from @vaadin/react-components/Select.js. Co-Authored-By: Claude Fable 5 --- scripts/generator.ts | 8 +++++++- test/typings/SelectItem.tsx | 16 ++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) create mode 100644 test/typings/SelectItem.tsx diff --git a/scripts/generator.ts b/scripts/generator.ts index d3399bf5..414f48a5 100644 --- a/scripts/generator.ts +++ b/scripts/generator.ts @@ -419,7 +419,13 @@ const sourceFiles = Array.from(elementFilesMap.entries(), ([element, data]) => g const elementNames = sourceFiles.map(({ fileName }) => basename(fileName, '.ts')); function generateIndexFile(elementNames: readonly string[], extension: string): SourceFile { - const sourceLines = [...elementNames.map((elementName) => `export * from './${elementName}.js';`)]; + const sourceLines = [ + ...elementNames.map((elementName) => `export * from './${elementName}.js';`), + // Explicit re-exports beat star exports per-name in TypeScript, so these deterministically + // resolve each component name (e.g. `SelectItem`) even if another module's `export *` chain + // re-exports a colliding name (e.g. a deprecated type from a web component package). + ...elementNames.map((elementName) => `export { ${elementName} } from './${elementName}.js';`), + ]; return ts.createSourceFile( resolve(packageDir, `index.${extension}`), diff --git a/test/typings/SelectItem.tsx b/test/typings/SelectItem.tsx new file mode 100644 index 00000000..61677017 --- /dev/null +++ b/test/typings/SelectItem.tsx @@ -0,0 +1,16 @@ +import { SelectItem, type SelectItemData } from '@vaadin/react-components'; +import type { SelectItem as SelectItemType } from '@vaadin/react-components/Select.js'; + +// `SelectItem` must resolve to the React component and work in value/JSX position. +const element = x; + +// `SelectItemData` must still work in type position (unaffected by the collision fix). +const items: SelectItemData[] = []; + +// The deprecated `SelectItem` type is intentionally no longer exported from the barrel; +// `SelectItem` now refers only to the component, so using it as a type must fail to compile. +// @ts-expect-error — `SelectItem` is a value (the component) in the barrel, not a type. +let deprecated: SelectItem[]; + +// Escape hatch: the deprecated type is still importable directly from the Select.js subpath. +let stillWorks: SelectItemType[] = [];