Skip to content

Commit

Permalink
feat: generalize function component types
Browse files Browse the repository at this point in the history
  • Loading branch information
Luke-zhang-04 committed Apr 7, 2024
1 parent 65e9416 commit a49bc37
Show file tree
Hide file tree
Showing 3 changed files with 14 additions and 34 deletions.
42 changes: 11 additions & 31 deletions src/createElement.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import {bindChildren, bindProps} from "./utils"
// TODO: make children optional
export type FunctionComponent<
Props extends {} | null | undefined,
Children extends ChildrenType = ChildrenType,
Children extends unknown[] = ChildrenType,
Returns extends Node | JSX.Element = JSX.Element,
> = (props: Props, ...children: Children) => Returns

Expand Down Expand Up @@ -130,32 +130,15 @@ export function createElement(
* @throws {Error} - If `tagNameOrFunction` is not a string or function, an errow is thrown
*/
export function createElement<
Props extends {} | null | undefined,
Children extends ChildrenType,
Returns extends Node | JSX.Element,
>(
func: FunctionComponent<Props, Children, Returns>,
props?: Props | null,
...children: Children
): Returns

/**
* Creates a function component
*
* @param func - Function component
* @param props - Props of function component
* @param children - Children of this element. Can be nothing, number, string, boolean, bigint, or
* more elements. An array will create multiple, flattened children.
* @returns Element
* @throws {Error} - If `tagNameOrFunction` is not a string or function, an errow is thrown
*/
export function createElement<
Props extends {} | null | undefined,
Props extends {} | null,
Children extends unknown[],
Returns extends Node | JSX.Element,
>(
func: FunctionComponent<Props, ChildrenType, Returns>,
props?: Props | null,
...children: ChildrenType
...[func, props, ...children]: [
func: FunctionComponent<Props, Children, Returns>,
...(Props extends null ? [props?: Props | undefined] : [props: Props]),
...children: Children,
]
): Returns

/**
Expand All @@ -170,12 +153,9 @@ export function createElement<
* @returns Element
* @throws {Error} - If `tagNameOrFunction` is not a string or function, an errow is thrown
*/
export function createElement<
T extends string | {[key: string]: unknown} | null | undefined,
Returns = void,
>(
export function createElement<T extends string | {[key: string]: unknown} | null, Returns = void>(
tagNameOrFunction: T | ((_props: T, ..._children: ChildrenType) => Returns),
props?: HTMLElementProps[T extends string ? T : ""] | null | T,
props?: HTMLElementProps[T extends string ? T : ""] | null | T | undefined,
...children: ChildrenType
): Element | Returns {
if (typeof tagNameOrFunction === "string") {
Expand All @@ -198,7 +178,7 @@ export function createElement<
} else if (typeof tagNameOrFunction === "function") {
// If `tagNameOrFunction` is a function, then the previous overload should've enforced that
// the props are set by the function (`T`)
return tagNameOrFunction(props as T, children)
return tagNameOrFunction((props ?? null) as T, children)
}

throw new Error(`Invalid element type ${typeof tagNameOrFunction}: ${tagNameOrFunction}`)
Expand Down
4 changes: 2 additions & 2 deletions src/fragment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ interface FragmentProps {
}

/* eslint-disable @typescript-eslint/naming-convention */
export const Fragment: FC<FragmentProps | null | undefined, ChildrenType, DocumentFragment> = (
props?,
export const Fragment: FC<FragmentProps | null, ChildrenType, DocumentFragment> = (
props,
...children
) => {
const documentFragment = document.createDocumentFragment()
Expand Down
2 changes: 1 addition & 1 deletion src/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import type {Ref} from "../createRef"
export type ChildType = Node | boolean | number | BigInt | string | null | undefined

/** All types the children parameter can be */
export type ChildrenType = ChildrenType[] | ChildType[]
export type ChildrenType = (ChildrenType | ChildType)[]

export interface EventMap extends HTMLElementEventMap, HTMLMediaElementEventMap {
/* eslint-disable-next-line @typescript-eslint/naming-convention */
Expand Down

0 comments on commit a49bc37

Please sign in to comment.