组件 Props 与 TypeScript 类型
本教程共 56 篇 · 第 8 篇 · 更新于 2026-08-07 · 约 10 分钟阅读
本节目标:学会让
.astro组件接收外部传进来的参数(Props),用Astro.props取值,并用 TypeScript 给参数加类型检查与默认值。
组件要“可复用”,关键得能接收不同参数。比如一个“标题组件”,这次传“你好”,下次传“欢迎”,它就该显示不同文字。Astro 里,这种从外面传进来的参数叫 Props(property 的简写,就是“组件的属性”)。
Props 从哪来
当你在别处这样用一个组件:
<GreetingHeadline greeting="Howdy" name="Partner" />
那两个 greeting="..." 和 name="..." 就是传给组件的 Props。在组件内部,它们都能从全局对象 Astro.props 里拿到。
看一个接收两个 Props 的组件:
---
// 用法:<GreetingHeadline greeting="Howdy" name="Partner" />
const { greeting, name } = Astro.props;
---
<h2>{greeting}, {name}!</h2>
写法是:在 frontmatter 里从 Astro.props 把要用的字段“解构”出来,然后模板直接 {greeting}、{name} 引用。
在别处传入 Props
组件自己定义好接收哪些 Props 后,在另一个组件、布局或页面里引入它,就能像写 HTML 属性一样传值:
---
import GreetingHeadline from './GreetingHeadline.astro';
const name = 'Astro';
---
<h1>Greeting Card</h1>
<GreetingHeadline greeting="Hi" name={name} />
<p>I hope you have a wonderful day!</p>
这里有个细节:greeting="Hi" 是写死的字符串;name={name} 用 {} 包了一个脚本里的变量。两种都合法——字符串直接写,变量用 {} 传。
用 TypeScript 给 Props 加类型
光接收还不够稳。万一调用方把 name 漏了、或者传了个数字进来,页面可能出怪问题。Astro 支持用 TypeScript(给 JavaScript 加“类型”的语言,能在写代码时发现类型错误)来约束 Props。
做法是:在 frontmatter 里定义一个叫 Props 的接口(interface),列出每个参数叫什么、是什么类型。Astro 会自动识别这个 Props 接口,给你类型提示和报错。
---
interface Props {
name: string; // name 必填,必须是字符串
greeting?: string; // greeting 可选(带问号),字符串
}
const { greeting = "Hello", name } = Astro.props;
---
<h2>{greeting}, {name}!</h2>
这段里的 interface Props 就是类型契约:
name: string表示name必传,且得是字符串;greeting?: string的问号表示“可选”,不传也不会报错。
如果你传 <GreetingHeadline name={123} />,由于 name 被声明成 string,TypeScript 会提示类型不对。这能在写代码阶段就拦住很多低级错误,对初学者非常友好。
Note你不用专门学透 TypeScript 也能用这招。记住一条:写组件时顺手用
interface Props { ... }把参数“登记”一下,Astro 就会替你看着类型。这是 Astro 项目里约定俗成的写法。
给 Props 设默认值
很多时候,你希望某个参数“不传就用个默认”。解构时直接赋值即可:
---
const { greeting = "Hello", name } = Astro.props;
---
<h2>{greeting}, {name}!</h2>
这里 greeting 没传时,就自动是 "Hello"。结合上一节的接口,还能给可选参数同时设默认:
---
interface Props {
name: string;
greeting?: string;
}
const { greeting = "Hello", name } = Astro.props;
---
<h2>{greeting}, {name}!</h2>
如果调用方没给 greeting,页面显示的就是 Hello, xxx!。
不写 TypeScript 时也能设默认,接口只是可选的“加强版”:
---
const { greeting = "Hello", name = "Astronaut" } = Astro.props;
---
<h2>{greeting}, {name}!</h2>
这回 name 也带默认值 "Astronaut",谁都不传也能正常渲染。
不写 TypeScript 也完全能用
前面那套 interface Props 是“加强版”。即使你完全不写类型,Props 照样工作——只是少了编译期的类型检查:
---
const { greeting = "Hello", name } = Astro.props;
---
<h2>{greeting}, {name}!</h2>
新手阶段可以先不碰 TypeScript,等熟悉了再回头加接口,Astro 完全兼容两种写法。
传递对象或数组作为 Props
Props 不限于字符串、数字,也能传整个对象或数组。类型里把结构写清楚即可:
---
interface Props {
user: { name: string; age: number };
}
const { user } = Astro.props;
---
<p>{user.name} 今年 {user.age} 岁</p>
调用时把对象直接写进 {}:
<ProfileCard user={{ name: "小明", age: 18 }} />
数组同理,类型写成 string[] 或 { ... }[] 都行。这样组件就能接收一整份结构化数据。
解构时给 Props 改名
偶尔外部传来的参数名,和你脚本里想用的变量名冲突,解构时可以顺手改名:
---
const { name: userName } = Astro.props;
---
<h2>你好,{userName}</h2>
这里外部仍传 name="...",组件内部叫它 userName,互不打架。
用 …rest 转发剩余属性
有时你想把“除了已知参数外、剩下所有属性”一股脑传给某个子元素。解构时用 ...rest 收集剩余项即可:
---
const { title, ...rest } = Astro.props;
---
<div {...rest}>{title}</div>
这里的 rest 是一个对象,装着除 title 外所有传进来的属性,{...rest} 再把它们铺回 <div> 上。第 11 章给子组件传 class 时用的就是这个技巧。
Props 是只读的
要记住:Astro.props 是只读的,不要试图直接改它里面的字段。如果想基于某个参数算出新值,先拷到自己的变量里再改:
---
const { name } = Astro.props;
const displayName = name.toUpperCase(); // 复制后再加工
---
<h2>{displayName}</h2>
直接写 Astro.props.name = ... 不会按你预期工作,还容易踩坑。养成“先复制、再加工”的习惯,代码更稳。
把所有 Props 整体往下传
偶尔你需要把当前组件收到的全部 Props,原样转发给另一个子组件。用展开语法一行搞定:
<ChildComponent {...Astro.props} />
这在做“包装组件”时很常见:外层只加一点样式或逻辑,其余参数原封不动交给内层。
必填还是可选?怎么设计
设计组件接口时,有个实用原则:高频必填的字段设成必填(不带问号),可有可无的设成可选并给默认值。比如一个“用户卡片”,name 几乎每次都要,就必填;avatar 头像没有时显示默认图,就可选加默认。这样调用方用起来既灵活又不会漏掉关键信息。接口写清楚后,代码编辑器还会给你自动补全和悬停提示,写调用代码更省心,这也是推荐用 TypeScript 描述 Props 的隐形好处。
一个含多参数的完整示例
把前面几点合起来,一个“带类型、带默认、可复用”的标题组件就长这样:
---
// GreetingHeadline.astro
interface Props {
name: string;
greeting?: string;
}
const { greeting = "Hello", name } = Astro.props;
---
<h2>{greeting}, {name}!</h2>
调用方可以自由组合:
<GreetingHeadline name="码上学" />
<GreetingHeadline greeting="Hi" name="小明" />
第一行用默认问候语,第二行自定义。组件本身一次写好,到处复用。
Tip把“会变化的数据”都做成 Props,是写好 Astro 组件的习惯。这样组件像积木一样,换个参数就换副面孔,不用复制粘贴改代码。
Astro 怎么认出 Props 接口
你可能会好奇:我写的是 interface Props,Astro 怎么知道「这个接口就是给 Props 用的」?
规则很简单:Astro 会在组件脚本里自动找一个名字就叫 Props 的接口(或类型别名),把它当成这个组件的参数契约。所以请固定用 Props 这个名,别写成 MyProps、HeadlineProps 之类——换名字 Astro 就不认了,类型检查会失效。
---
// ✅ 正确:名字是 Props,Astro 认
interface Props {
title: string;
}
const { title } = Astro.props;
---
如果你确实想用别的名字,可以显式标注组件的 Props 类型,但新手阶段没必要折腾,老老实实写 Props 最省事。
用 astro check 把错误拦在写代码时
类型写好了,怎么确认没写错?除了编辑器里飘红提示,你还能在终端跑一条命令统一检查:
npm run check
它背后是 astro check,会扫描项目里所有 .astro 和 .ts 文件,把类型错误、明显的写法问题一次性列出来。比如你把 name 传成了数字、漏了必填参数,它都会报。
建议养成习惯:写完一组组件、准备构建前,先跑一次 astro check。比起等构建报错或上线后出怪问题,提前查一遍省心得多。
小结
Props 是组件之间“传数据”的通道:在外面像写属性一样传,在里面从 Astro.props 解构取。用 interface Props 加 TypeScript 类型,能让传参出错在写代码时就被发现;解构时赋值则能给参数设默认值。下一章讲另一个组件间通信的机制——插槽(slot),它负责把“一整块 HTML 内容”塞进组件的指定位置。