type AnyProps = Record; function defaultClassMergeFn(...classes: string[]): string { return classes .map((s) => s.trim()) .filter(Boolean) .join(" ") .trim(); } // 工具类型 type UnionToIntersection = (U extends any ? (k: U) => void : never) extends (k: infer I) => void ? I : never; // 泛型入口 export function mergeProps< T extends AnyProps[] >( ...args: [...T] ): UnionToIntersection; export function mergeProps< T extends AnyProps[] >( options: { classMergeFn: (...cls: string[]) => string }, ...args: [...T] ): UnionToIntersection; export function mergeProps( arg1: any, ...rest: any[] ): any { let options = { classMergeFn: defaultClassMergeFn, }; let propsList: AnyProps[]; if ( arg1 && typeof arg1 === "object" && !Array.isArray(arg1) && "classMergeFn" in arg1 && typeof arg1.classMergeFn === "function" ) { options = arg1; propsList = rest; } else { propsList = [arg1, ...rest]; } const result: AnyProps = {}; const eventHandlers = new Map(); const refs: any[] = []; for (const props of propsList) { if (!props) continue; if (props.className) { result.className = options.classMergeFn( result.className ?? "", props.className, ); } if (props.style) { result.style = { ...(result.style ?? {}), ...props.style }; } if (props.ref) { refs.push(props.ref); } for (const key of Object.keys(props)) { if (key.startsWith("on") && typeof props[key] === "function") { if (!eventHandlers.has(key)) { eventHandlers.set(key, []); } eventHandlers.get(key)!.push(props[key]); } else if (key !== "ref" && key !== "className" && key !== "style") { result[key] = props[key]; } } } // refs if (refs.length === 1) { result.ref = refs[0]; } else if (refs.length > 1) { result.ref = (node: any) => { refs.forEach((ref) => { if (typeof ref === "function") ref(node); else if (ref) ref.current = node; }); }; } // events eventHandlers.forEach((handlers, key) => { result[key] = (...args: any[]) => { handlers.forEach((fn) => fn(...args)); }; }); return result; }