packages/react-components/react-utilities/scripts/README.md
Note: This solution is not currently used in the codebase. We found an alternative workaround using type utilities in
@packages/react-components/react-utilities/src/utils/types.ts:tsexport type JSXIntrinsicElementKeys = Exclude<React.ElementType, React.ComponentType>; export type JSXIntrinsicElement<Element extends JSXIntrinsicElementKeys> = React.ComponentProps<Element>;The script is kept for future reference in case the current workaround doesn't work with future React versions.
This directory contains TypeScript transform scripts that extract actual JSX intrinsic element names from React type definitions and emit them as literal string unions instead of preserving keyof JSX.IntrinsicElements references.
TypeScript declaration files typically preserve type expressions like keyof JSX.IntrinsicElements rather than expanding them to the actual union of element names. This transformer ensures that consumers of the library get the fully expanded string union for better IntelliSense and type checking.
The advanced script handles both React type definition structures:
declare global {
namespace JSX {
interface IntrinsicElements {
div: React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>;
// ... other elements
}
}
}
declare namespace React {
namespace JSX {
interface IntrinsicElements {
div: React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>;
// ... other elements
}
}
}
yarn nx run react-utilities:prebuild
npx tsx scripts/expand-jsx-intrinsic-elements.ts --target-file ./generated-types.ts
The script generates two complementary types to handle React version compatibility:
JSXIntrinsicElementKeysCompat--omit-elements)keyof JSX.IntrinsicElements usageJSXIntrinsicElementKeysLatestJSXIntrinsicElementKeysCompatThis approach ensures smooth transitions between React versions while maintaining type safety.
The script supports command line arguments for customization:
--target-file, -t: Output file path (required)--react-types-path, -r: Path to the React types directory (auto-detected if not provided)--omit-elements, -o: Comma-separated list of elements to exclude from the generated union--help, -h: Show help message# Show help
npx tsx scripts/expand-jsx-intrinsic-elements.ts --help
# Basic usage with required target file
npx tsx scripts/expand-jsx-intrinsic-elements.ts --target-file ./generated-types.ts
# Exclude specific elements from the generated union
npx tsx scripts/expand-jsx-intrinsic-elements.ts --target-file ./generated-types.ts --omit-elements div,span,p
# Use custom React types path
npx tsx scripts/expand-jsx-intrinsic-elements.ts --target-file ./generated-types.ts --react-types-path /path/to/react/types
# Combine multiple options
npx tsx scripts/expand-jsx-intrinsic-elements.ts --target-file ./custom-types.ts --omit-elements set,mpath,center,search
Input:
export type JSXIntrinsicElementKeys = keyof JSX.IntrinsicElements;
Output (Dual Type Generation):
The script now generates two complementary types to ensure compatibility across React versions:
/**
* Unwrapped type for 'keyof JSX.IntrinsicElement'. (Backwards compatible with older versions of @types/react)
*/
export type JSXIntrinsicElementKeysCompat =
| 'a'
| 'abbr'
| 'address'
| 'animate'
// ... filtered elements (178 total, minus any omitted elements)
| 'video'
| 'view'
| 'wbr'
| 'webview';
/**
* Unwrapped type for 'keyof JSX.IntrinsicElement'
*/
export type JSXIntrinsicElementKeysLatest =
| 'set' // Previously omitted elements (if --omit-elements was used)
| 'mpath'
| 'center'
| 'search'
| JSXIntrinsicElementKeysCompat; // Union with all compatible elements
This dual approach provides:
JSXIntrinsicElementKeysCompat: Filtered elements for React 17 compatibilityJSXIntrinsicElementKeysLatest: Complete element set for React 18+ projectsJSX.IntrinsicElements first, then React.JSX.IntrinsicElements if neededJSXIntrinsicElementKeysCompat: Backwards compatible with React 17 (filtered elements)JSXIntrinsicElementKeysLatest: Full element set including previously omitted elementsomitElements option for backward compatibilityThe advanced script uses a sophisticated TypeChecker-only approach:
.tsx file with type aliases:
type TestIntrinsicElements = JSX.IntrinsicElements;
type TestReactIntrinsicElements = React.JSX.IntrinsicElements;
The transformed types are automatically included in the build process:
src/utils/generated-types.ts with dual type definitionssrc/utils/types.ts re-exports both generated types:
JSXIntrinsicElementKeysCompat for React 17 compatibilityJSXIntrinsicElementKeysLatest for React 18+ projectssrc/index.ts exports both types to the public APIkeyof operations at compile timeAuto updates types via prebuild target to ensure that:
JSXIntrinsicElementKeysCompat and JSXIntrinsicElementKeysLatest stay synchronized with React type updatesgenerate-api is run