Reputation: 21030
I am creating an component library with Preact and TypeScript. I have an icon component which can be used like:
<SVGIcon name='camera' width={16} height={24} />
And, it is implemented as:
export interface SVGIconProps {
class?: string;
width?: string;
height?: string;
name: string;
};
export function SVGIcon(props: SVGIconProps) { /* return svg; */ }
In to provide better intellisense for library users, I want to narrow the type of name
prop to a limited set of string literals (basically show only allowed names for icons). I can, of course, use string literals that library is providing; however, the user is also allowed to dynamically register his own additional icon sets using a register function like:
registerIcon('icon-name', jsxFunctionReturningSVGFragment);
The registerIcon
function add the icon and its JSX function to an internal cache (instance of ES Map
).
That question is how can I retain the narrow typing and provide auto-complete/intellisense for library users considering the fact that they can add one or more icons when consuming the library?
Is it possible to declare a dummy interface/type say MyLibIconSet
at a library level which the user of the library should then override in his code-base before using the library? Something similar to how we do for declaration merging or using Global augmentation for patching missing types?
Upvotes: 1
Views: 250
Reputation: 20401
I think this can be achieved with declaration merging.
You could define an interface that has a member for each possible icon. The type would be whatever you like in this case:
export interface SVGPossibleIcons {
thumbsUp: string;
thumbsDown: string;
roflSmiley: string;
}
Then you could define your props like this:
export interface SVGIconProps {
class?: string;
width?: string;
height?: string;
name: keyof SVGPossibleIcons;
}
The user of the library then has to extend that interface with his/her own icons like this:
declare module "YourSVGModuleName" {
export interface SVGPossibleIcons {
anotherCustomSmiley: string;
}
}
Upvotes: 2