splitProps: separar lo propio de lo que reenvías
splitProps parte un objeto de props en grupos que siguen siendo proxies reactivos, para consumir unas props y reenviar el resto con spread al DOM o a un hijo sin romper la reactividad. Además infiere los tipos de cada grupo, algo que la destructuración con rest jamás podría dar sin congelar el objeto entero.
El problema del envoltorio que reenvía
El patrón es universal: un Boton que envuelve al <button> nativo, añade una clase y una variante, y quiere que cualquier otra prop —onClick, disabled, aria-label, type— llegue intacta al elemento real. Necesitas apartar variante y class, y hacer spread del resto:
// ROTO: el rest lee y congela todas las propsfunction Boton(props) { const { variante, class: clase, ...resto } = props; // dispara todos los getters return <button class={`btn-${variante} ${clase}`} {...resto} />; // resto es una foto}Ese {...resto} reenvía valores muertos: si el padre cambia disabled más tarde, el <button> no se entera. El spread de un objeto plano rompe justo lo que un envoltorio debe preservar: la transparencia reactiva hacia el elemento que envuelve.
splitProps: un rest que no congela
splitProps(props, claves) recibe el objeto de props y uno o más arrays de claves. Devuelve un array de proxies: uno por cada grupo de claves que pediste, y un último proxy con todo lo que sobró. Cada proxy conserva los getters, así que leer de cualquiera de ellos sigue siendo una lectura viva.
import { splitProps } from "solid-js";function Boton(props: JSX.ButtonHTMLAttributes<HTMLButtonElement> & { variante: string }) { const [propio, resto] = splitProps(props, ["variante", "class"]); // ┃ solo variante y class ┃ todo lo demás, reactivo return ( <button class={`btn-${propio.variante} ${propio.class ?? ""}`} {...resto} /> );}Ahora {...resto} es un proxy: el compilador de Solid hace el spread de forma reactiva, de modo que si el padre cambia disabled u onClick, el <button> lo recibe al instante. Has consumido dos props y reenviado el universo restante sin que ninguna pierda su cable con la fuente.
Fíjate en un matiz clave: propio y resto no son objetos nuevos con datos copiados, sino vistas —proxies— sobre las mismas props del padre. No hay clonación ni coste de memoria en el reparto.
Eso distingue a splitProps de cualquier utilidad casera de “omitir claves”: las artesanales copian y congelan; esta reencamina y mantiene vivas las aristas a ambos lados.
Varios grupos a la vez
Puedes pedir más de un grupo pasando varios arrays de claves; splitProps devuelve un proxy por cada uno, en orden, y el rest al final. Es útil cuando repartes props entre varios destinos: unas para estilos, otras para eventos, el resto al elemento.
const [estilo, eventos, resto] = splitProps( props, ["class", "style"], // grupo 1: presentación ["onClick", "onFocus"], // grupo 2: comportamiento);// estilo.class, eventos.onClick, {...resto} — tres proxies vivosUna clave solo cae en el primer grupo que la reclama; el rest recoge lo que nadie pidió. Así puedes dirigir cada familia de props a su sitio sin duplicar ni perder reactividad en el camino.
El caso estrella es el componente polimórfico: un Box que acepta una prop as para elegir su etiqueta y reenvía todo lo demás al elemento resultante. splitProps aparta as y children, y el resto viaja íntegro y reactivo:
function Box(props) { const [propio, resto] = splitProps(props, ["as", "children"]); const Tag = () => propio.as ?? "div"; return <Dynamic component={Tag()} {...resto}>{propio.children}</Dynamic>;}El componente Dynamic llega en 7.5; aquí basta ver que resto reenvía atributos reactivos a la etiqueta que as decida, y que cambiar as en caliente cambia el elemento sin tocar el resto de las props.
Tipar el resultado
En TypeScript, splitProps no te pide anotar nada: sus genéricos derivan el tipo de cada grupo a partir de la lista de claves. El primer proxy recibe un Pick de las claves que extrajiste; el rest recibe el Omit complementario. Los conjuntos son disjuntos también en el plano de tipos, así que el compilador te protege de leer en el sitio equivocado.
type BotonProps = JSX.ButtonHTMLAttributes<HTMLButtonElement> & { variante: "solido" | "fantasma"; cargando?: boolean;};function Boton(props: BotonProps) { const [propio, resto] = splitProps(props, ["variante", "cargando"]); // propio: Pick<BotonProps, "variante" | "cargando"> // resto: Omit<BotonProps, "variante" | "cargando"> -> atributos nativos del button return ( <button disabled={propio.cargando} {...resto}> {propio.variante === "solido" ? "OK" : "..."} </button> );}resto queda tipado exactamente como los atributos nativos de <button>, que es justo lo que el spread necesita para ser type-safe: no puedes reenviar al DOM una prop que el elemento no admite sin que el compilador te frene. Esta inferencia por diferencia de conjuntos es la que la destructuración con rest daría en tipos, pero sin la reactividad; splitProps te entrega las dos cosas a la vez, y por eso es el cimiento de los sistemas de componentes tipados en Solid.