Recibir props y tiparlas con interface Props
Cómo un componente .astro recibe datos de su padre mediante Astro.props, la sintaxis de atributos frente a expresiones, el tipado del contrato con interface Props, y por qué el flujo de datos en Astro va siempre de padre a hijo.
Un componente aislado sirve de poco: su valor aparece cuando otro le pasa datos y lo reutiliza con variaciones. Ese canal de entrada son las props, el contrato por el que un padre configura a su hijo. En Astro las props se declaran como atributos, se reciben en Astro.props y se tipan con una interfaz que el framework reconoce por convención. Dominar ese contrato es dominar cómo se componen las piezas de una interfaz.
- Pasar datos a un componente con la sintaxis de atributos y de expresiones.
- Recibir esos datos desestructurando
Astro.propsen el frontmatter. - Tipar el contrato del componente con una
interface Props. - Comprender por qué el flujo de datos en Astro va siempre de padre a hijo.
Pasar props: atributos y expresiones
Cuando un componente usa a otro, le pasa datos con una sintaxis que imita los atributos de HTML. Cada atributo es una prop, y su nombre es la llave con la que el hijo la recibirá después.
---
// src/pages/index.astro
import Saludo from '../components/Saludo.astro';
---
<Saludo nombre="Ada" veces={3} />
Hay dos maneras de dar valor a una prop, y la distinción es la misma que gobierna todo el templating de Astro. Un valor literal de texto se escribe entre comillas, como nombre="Ada". Cualquier otro tipo —número, booleano, array, objeto o variable— se envuelve en llaves, porque dentro de ellas Astro evalúa una expresión de JavaScript: veces={3}, activo={true}, datos={usuario}.
Olvidar esa regla es el error más común al empezar. Escribir veces="3" no pasa el número tres, sino la cadena de texto tres, y el hijo recibirá un tipo distinto del que espera. Las comillas son para texto; las llaves, para todo lo demás.
activo={true} pasa el booleano verdadero; activo="true" pasa la cadena de texto true, que en JavaScript es siempre veraz aunque diga false. Este desajuste produce fallos silenciosos: el componente parece recibir el dato, pero su tipo está corrompido. Ante la duda, si no es texto plano, usa llaves.
Recibir props: Astro.props
Del otro lado del contrato, el hijo lee todo lo que le llega a través de un único objeto: Astro.props. Cada atributo que puso el padre aparece como una propiedad de ese objeto, con el mismo nombre. Lo idiomático es desestructurarlo en la primera línea del frontmatter.
---
// src/components/Saludo.astro
const { nombre, veces } = Astro.props;
---
{Array.from({ length: veces }).map(() => <p>Hola, {nombre}</p>)}
La desestructuración no es obligatoria —podrías leer Astro.props.nombre cada vez— pero declarar las props al principio documenta de un vistazo qué espera el componente. Es la cabecera de su contrato, escrita en la primera línea que cualquiera leerá.
A diferencia de un atributo HTML nativo, que suele ir en kebab-case, una prop de componente conserva el nombre exacto con que la escribes. <Ficha fechaAlta={hoy} /> llega como Astro.props.fechaAlta, en camelCase. Astro no transforma la clave: el nombre que pones al pasar la prop es el nombre con que la lees. Elige un convenio, normalmente camelCase, y sé consistente en todo el árbol.
Conviene fijar un límite conceptual: Astro.props existe solo en componentes, no en páginas. Una página es la raíz del árbol de render y nadie la instancia con atributos, así que no recibe props de un padre; lo que consume son parámetros de ruta y datos que ella misma carga. Las props son el lenguaje entre componentes, no la puerta de entrada del sitio.
Tipar el contrato: interface Props
Astro reserva un nombre especial dentro del frontmatter: si declaras una interfaz llamada Props, el framework la usa para tipar Astro.props automáticamente. No hay que importarla ni registrarla; la convención del nombre basta.
---
// src/components/Saludo.astro
interface Props {
nombre: string;
veces: number;
}
const { nombre, veces } = Astro.props;
---
A partir de esa declaración, el contrato deja de ser una promesa verbal y pasa a estar vigilado por el compilador. Si una página usa <Saludo /> sin nombre, o le pasa veces="tres" en vez de un número, el editor lo subraya y astro check lo reporta antes de ejecutar nada. El tipado convierte un acuerdo tácito en un contrato ejecutable.
El padre
Declara los atributos al instanciar el hijo. Es quien decide los valores concretos en cada uso.
El hijo
Declara interface Props y lee Astro.props. Define la forma que acepta, no los valores.
El reparto de responsabilidades es nítido: el hijo define la forma del contrato con su interfaz; el padre aporta los valores en cada instancia. Uno dice qué tipos admite; el otro, con qué datos concretos lo llena. Por eso un mismo componente rinde distinto en cada página sin cambiar una línea de su código.
El flujo de datos: de padre a hijo
Las props viajan en una sola dirección: descendente. El padre configura al hijo, nunca al revés. Dentro del hijo, Astro.props es de solo lectura conceptualmente: reasignar esas variables no envía nada de vuelta al padre ni altera otras instancias del componente.
flowchart TD P[Componente padre] -->|nombre y veces| H[Componente hijo] H --> PR[Astro.props tipado por interface Props] PR --> R[HTML renderizado] style P fill:#89b4fa,color:#11111b style R fill:#a6e3a1,color:#11111b
Esa unidireccionalidad no es una limitación, sino la fuente de una propiedad valiosa: el render es predecible. Como los datos solo bajan, para saber qué muestra un componente basta con mirar quién lo instancia y con qué valores. No hay canales ocultos por los que un hijo modifique a su padre a distancia. El árbol de componentes se lee de arriba abajo, igual que fluyen los datos.
Hay una segunda diferencia frente a los frameworks de cliente. Las props de Astro se evalúan en el servidor, en tiempo de build o de petición, no de forma reactiva en el navegador. Cambiar un valor no vuelve a renderizar nada en vivo: el HTML se produce una vez, con los datos que había en ese momento, y se envía ya resuelto. Las props configuran la generación del HTML, no una interfaz que reacciona sola.
Es tentador pensar en las props como mensajes que el padre envía al hijo, pero esa metáfora enturbia lo esencial. Una prop no es un mensaje en tránsito: es una cláusula de un contrato que el hijo publica y el padre firma. El hijo, con su interface Props, declara qué necesita para funcionar —qué nombres, qué tipos, qué es obligatorio—; el padre, al instanciarlo, se compromete a cumplirlo. El compilador es el notario que verifica la firma antes de que nada se ejecute. Esta lectura cambia cómo diseñas componentes. Dejas de preguntarte qué datos mandar y empiezas a preguntarte qué contrato ofrecer: cuál es la interfaz mínima y honesta que hace útil a esta pieza sin atarla a un uso concreto. Un buen contrato de props es estrecho y explícito —pide justo lo que usa, con tipos precisos— porque cada prop es una obligación que impones a todo el que quiera reutilizar el componente. Y como el flujo va en una sola dirección, el contrato también fija la responsabilidad: el estado vive arriba, las props lo distribuyen hacia abajo, y ningún hijo puede corromper la fuente. Componer interfaces en Astro no es cablear datos entre piezas, sino diseñar una jerarquía de contratos donde cada nivel promete poco, cumple exactamente lo que promete, y confía el resto a quien está por encima. Esa disciplina —contratos estrechos, datos que solo bajan, tipos que vigilan la frontera— es lo que hace que un árbol de componentes crezca sin volverse un laberinto.
- Crea un componente
Tarjeta.astrocon unainterface Propsque exijatitulode tipo texto ydestacadade tipo booleano. - Úsalo desde una página pasando
titulo="Hola"ydestacada={true}; observa el autocompletado de las props en el editor. - Cambia a propósito
destacada={true}pordestacada="true"y comprueba queastro checkprotesta por el tipo. - Instancia el componente dos veces con títulos distintos y confirma que el mismo código produce dos salidas: esa es la reutilización que habilita el contrato.