首页
/ Svelte Legacy 组件 props 详解:export let 的声明、默认值与组件 API 导出

Svelte Legacy 组件 props 详解:export let 的声明、默认值与组件 API 导出

2026-09-06 13:43:05作者:裘旻烁

本文基于 Svelte 官方文档 documentation/docs/99-legacy/03-legacy-export-let.md 展开,完整讲解 legacy 模式(非 runes 模式)下 export let 声明组件 props 的全部用法:默认值语义、必需 prop 的缺失警告与抑制方式、const/class/function 声明成为组件 API 而非 prop 的区别,以及用 export { x as y } 重命名 prop(如处理保留字)的技巧。读完后,你可以准确判断一段 legacy 组件脚本中哪些标识符是 prop、哪些是 API 导出,并能对照 Svelte 编译器源码理解这些规则的判定依据。

1. 背景:runes 与 legacy 两种 props 声明方式

在 runes 模式(Svelte 5 的默认推荐方式)下,组件 props 通过 $props() rune 声明,父组件传入的数据以解构形式接收:

<script>
	let { foo, bar = 'default value' } = $props();
</script>

而在 legacy 模式下,props 通过 export 关键字标记,并且可以带默认值

<script>
	export let foo;
	export let bar = 'default value';

	// 作为 props 传入的值
	// 在组件实例代码中立即可用
	console.log({ foo });
</script>

官方文档指出两者的一个关键行为差异(原文档中的 NOTE):

与 runes 模式不同,如果父组件把一个 prop 从“有值”改为 undefined,legacy 模式下的该 prop 不会回退到初始默认值。也就是说 bar = 'default value' 中的 'default value' 只在组件创建时该 prop 为 undefined 的情况下生效;之后父组件显式传 undefined 时,组件内拿到的就是 undefined,而不是 'default value'

这一点在混合 runes/legacy 代码库、或从 Svelte 4 迁移代码时尤其需要注意:不能假设两种模式的 props 回退行为一致。Svelte 5 迁移指南(documentation/docs/07-misc/07-v5-migration-guide.md)中 “export let → props”一节也说明了这一迁移关系,并提到exportlet曾是一个争议较大的API决策——你既可以把它理解为“导出”也可以理解为“导入”,而props” 一节也说明了这一迁移关系,并提到 `export let` 曾是一个争议较大的 API 决策——你既可以把它理解为“导出”也可以理解为“导入”,而 `props` 统一到了 rune 语义中。

2. 源码级机制:编译器如何判定 export let 是 prop

Svelte 编译器在 analyze 阶段(phases/2-analyze)对非 runes 组件的 <script> 体逐条扫描 ExportNamedDeclaration 节点,判定规则可以从 packages/svelte/src/compiler/phases/2-analyze/index.js 中直接读到(源码注释原话是 “every exported let or var declaration becomes a prop, everything else becomes an export”):

  • export let / export var 声明:绑定(binding)的 kind 被置为 bindable_prop,即该标识符是一个 prop,并且是可双向绑定的(父组件可以用 bind:foo={x});
  • export constexport functionexport class 声明:不成为 prop,而是被推入 analysis.exports,作为组件的具名导出(组件 API);
  • export { a as b } 这类重导出:如果 local 对应的是 let/var 绑定,同样标记为 bindable_prop,且当导出名与本地名不同时,记录 binding.prop_alias = 导出名;否则记为普通导出。

另外,任何 export let 的存在都会把组件标记为 analysis.needs_props = true

对应的错误检查逻辑在 packages/svelte/src/compiler/phases/2-analyze/visitors/ExportNamedDeclaration.js:runes 模式下禁止 export let,抛出 legacy_export_invalid 错误(“Cannot use export let in runes mode — use $props() instead”),错误定义见 packages/svelte/src/compiler/errors.js,对应的测试样例在 packages/svelte/tests/compiler-errors/samples/runes-export-let/_config.js

由此可以推断出两条实操结论:

  1. legacy 组件中只有 let/var 形式的导出是 propconst 导出永远是只读 API;
  2. prop 天然是双向可绑定的(bindable_prop),这是 legacy 模式相对 $props() 的一个便利性——在 runes 模式里需要 $bindable() 显式声明。

3. 默认值与“必需 prop”的缺失警告

3.1 默认值语义

如前所述,默认值仅在组件创建时该 prop 为 undefined 时使用。注意这与 JS 的解构默认值不同:export let bar = 'default value' 不是对 barbar ?? 'default value',而是初始赋值。

3.2 无默认值的 prop 视为 required

没有默认值的 prop 被视为必需(required)。如果父组件未提供值,Svelte 会在开发模式下打印警告。要抑制这个警告,可以把默认值显式设为 undefined

export let foo = undefined;

这样编译器就知道“这个 prop 允许为空”,不再把它当作漏传。

3.3 相关的编译期警告:export_let_unused

还有一个容易混淆的编译警告值得了解:export_let_unused,其消息定义为(见 packages/svelte/messages/compile-warnings/script.md):

Component has unused export property '%name%'. If it is for external reference only, please consider using export const %name%

它由 packages/svelte/src/compiler/phases/2-analyze/index.js 中的检查触发:遍历实例作用域,凡是 kindpropbindable_prop 且除声明与导出标记外没有任何引用的绑定,就会发出该警告。换句话说——你 export let 了却在模板和脚本里都没用它——要么它是多余的,要么它本应写成 export const。这对代码审查很实用:看到这条警告时,先确认该 prop 是否真的被外部 bind: 使用,若只是给外部引用则改用 const

4. 组件导出:const / class / function 不是 prop

官方文档的 “Component exports” 一节强调:导出的 constclassfunction 声明不被视为 prop,而是组件 API 的一部分。示例来自文档原文:

Greeter.svelte

<!--- file: Greeter.svelte--->
<script>
	export function greet(name) {
		alert(`hello ${name}!`);
	}
</script>

App.svelte

<!--- file: App.svelte --->
<script>
	import Greeter from './Greeter.svelte';

	let greeter;
</script>

<Greeter bind:this={greeter} />

<button on:click={() => greeter.greet('world')}>
	greet
</button>

通过 bind:this={greeter} 拿到组件实例引用后,就可以调用 greeter.greet('world')。这与第 2 节的源码判定一致:ExportNamedDeclarationFunctionDeclaration/ClassDeclaration/const 分支只会被推入 analysis.exports(见 packages/svelte/src/compiler/phases/2-analyze/index.js),不会触碰 props 机制。

需要注意的前提:bind:this 是 legacy 的实例访问方式;在 runes 模式下访问组件实例 API 有专门规范(参见 documentation/docs/06-runtime/04-imperative-component-api.md 中对 imperative component API 的说明),本文聚焦 legacy 语义。

5. 重命名 props:export 与声明分离

export 关键字也可以脱离声明单独出现。文档给出的典型场景是给保留字命名的 prop 重命名:

<!--- file: App.svelte --->
<script>
	/** @type {string} */
	let className;

	// 创建一个 `class` 属性,
	// 尽管它是保留字
	export { className as class };
</script>

此时对外暴露的 prop 名是 class(父组件写作 <App class="x" /> 或通过 spread 传入),而组件内部通过本地变量 className 使用它。对应源码逻辑:在 analyze 阶段处理 export { a as b } 时,若 alet/var 绑定则标记为 bindable_prop,且 b !== a 时设置 binding.prop_alias = bpackages/svelte/src/compiler/phases/2-analyze/index.js)。这个 prop_alias 字段正是后续 transform 阶段生成 props 接收代码、以及模板中按原始名称引用时进行映射的依据。

由此可以推断出 legacy 模式的完整心智模型:

写法 语义 可否 bind: 备注
export let foo; prop,required 未传值时开发环境警告
export let bar = 'x'; prop,带默认值 仅创建期为 undefined 时生效
export let foo = undefined; prop,可选 抑制 required 缺失警告
let x; export { x as class }; prop,对外名 class 处理保留字等场景
export const / function / class 组件 API 导出 通过实例引用访问

6. 与 runes 模式的互斥与迁移提示

7. 小结

  • legacy 模式 props = 实例作用域中被导出的 let/var 声明(含 export { x as y } 重命名),可双向绑定,默认值只在创建期为 undefined 时生效;父组件后续改传 undefined 不会回退默认值。
  • export const/function/class 是组件 API 而非 prop,经 bind:this 实例引用访问。
  • required prop 未传值会在开发环境警告,export let foo = undefined; 可显式标记为可选以消除警告;export_let_unused 警告则提示你“导出了却没用”,应考虑改为 const
  • runes 模式禁用 export letlegacy_export_invalid 编译错误),迁移路径是 $props()
登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.13 K
2.75 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
857
1.35 K
docsdocs
暂无描述
Markdown
897
5.8 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
529
593
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
915
1.83 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.58 K
1.01 K
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.35 K
1.46 K
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
1.01 K
515
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
547
388