TypeScript Icons: Strict Typing & Polymorphic Wrappers (2026)
Eliminate runtime SVG rendering bugs with strict TypeScript interfaces. Discover how typed icon properties, generic polymorphic components, and IDE autocompletion improve developer productivity.
How do you build a strictly typed polymorphic SVG icon component in TypeScript?
A strictly typed polymorphic SVG icon wrapper in TypeScript extends React.ComponentPropsWithoutRef<'svg'> while accepting a generic icon component type like LucideIcon. This centralizes default sizing, accessibility attributes (aria-hidden), and theme utility classes while maintaining full compile-time autocomplete and prop validation. Wrapping primitives ensures that design system tokens remain consistent across your engineering organization while preserving native SVG attribute passthrough.
// components/ui/icon.tsx
import React from 'react'
import { LucideIcon, LucideProps } from 'lucide-react'
export interface IconProps extends Omit<LucideProps, 'ref'> {
icon: LucideIcon
label?: string // Optional accessible label
className?: string
}
export function AppIcon({ icon: IconComponent, label, className = '', size = 20, ...rest }: IconProps) {
return (
<IconComponent
size={size}
className={className}
aria-hidden={!label}
aria-label={label}
role={label ? 'img' : 'presentation'}
{...rest}
/>
)
}
// Usage in your React / Next.js app:
// <AppIcon icon={Home} size={24} className="text-blue-500" label="Go to homepage" />Which icon libraries provide native TypeScript definition files?
Modern icon libraries including Lucide React, Heroicons, Tabler Icons, Radix Icons, and Phosphor Icons ship native `.d.ts` declaration files. These declarations provide instant IntelliSense in VS Code, type-safe prop interfaces, and strict prop checking under TypeScript 5+. The comparison table below highlights TypeScript support across major libraries:
| Library | Total Icons | License | TypeScript Declarations | Module Resolution | Primary NPM Package |
|---|---|---|---|---|---|
| Lucide Icons | 1,960 | ISC | Native .d.ts / .d.mts | Bundler & Node16 | lucide-react |
| Heroicons | 324 | MIT | Native .d.ts / .d.mts | Bundler & Node16 | @heroicons/react |
| Tabler Icons | 6,147 | MIT | Native .d.ts / .d.mts | Bundler & Node16 | @tabler/icons-react |
| PatternFly Icons | 2,884 | MIT | Native .d.ts / .d.mts | Bundler & Node16 | @patternfly/react-icons |
| Untitled UI Icons | 1,179 | MIT | Native .d.ts / .d.mts | Bundler & Node16 | @untitledui/icons |
| Phosphor Icons | 1,533 | MIT | Native .d.ts / .d.mts | Bundler & Node16 | @phosphor-icons/react |
| Radix Icons | 318 | MIT | Native .d.ts / .d.mts | Bundler & Node16 | @radix-ui/react-icons |
| Iconoir | 1,384 | MIT | Native .d.ts / .d.mts | Bundler & Node16 | iconoir-react |
Core Advantages of Native TypeScript Support
VS Code and JetBrains IDEs instantly suggest symbol names as you type, reducing typos and API lookups.
Catch invalid size strings, missing colors, or unsupported SVG stroke values at build-time.
Rename and migrate icon primitives across hundreds of files safely with automated TypeScript refactoring.
Hover over any icon component in your IDE to see its bounding box, stroke defaults, and tags.
Verified TypeScript Icon Libraries (11)
LIBRARIES REQUIRING MANUAL TYPE DEFINITIONS (7)
TypeScript & SVG Icons FAQ
What is the standard TypeScript type for React SVG icon components?
Most modern libraries export a dedicated prop interface (e.g., `LucideProps` from lucide-react) or extend standard SVG component props: `React.ComponentPropsWithoutRef<"svg"> & { size?: number | string; strokeWidth?: number | string }`. This ensures full compatibility with standard HTML SVG attributes.
How does verbatimModuleSyntax affect SVG icon imports in TypeScript 5+?
With `verbatimModuleSyntax: true` enabled in tsconfig.json, TypeScript strictly distinguishes type imports from runtime value imports. Value imports like `import { Home } from "lucide-react"` will be preserved as runtime JS, while type imports like `import type { LucideIcon } from "lucide-react"` are completely stripped at compile time.
How do I build a generic dynamic Icon component in TypeScript without bundling all icons?
Define an explicit string union type (e.g., `type IconName = "home" | "settings" | "user"`) and map each key to a statically imported component in an internal map object. TypeScript will provide strict compile-time autocomplete and prevent invalid string keys.
Why do some legacy icon packages have missing or broken .d.ts declaration files?
Older libraries published before the ESM migration frequently shipped CommonJS-only code or generated declarations with ambient namespaces that fail under strict modern `moduleResolution: "bundler"` or `"node16"`. All libraries highlighted on this page ship native .d.ts or .d.mts declarations.
Explore Next.js & React Guides
Learn how to render typed icons in Next.js Server Components and React.