Wasp 语言(.wasp DSL)完全指南:声明式配置与类型系统深度解析
2026/9/15 13:35:41 网站建设 项目流程

Wasp 语言(.wasp DSL)完全指南:声明式配置与类型系统深度解析

【免费下载链接】waspThe batteries-included full-stack framework for the AI era. Develop JS/TS web apps (React, Node.js, and Prisma) using declarative code that abstracts away complex full-stack features like auth, background jobs, RPC, email sending, end-to-end type safety, single-command deployment, and more.项目地址: https://gitcode.com/GitHub_Trending/wa/wasp

本文是 Wasp 全栈框架中Wasp 语言(.wasp 文件 DSL)的权威技术指南,讲解这门声明式、静态类型、面向 Web 应用的领域特定语言的核心语法、完整类型体系与编译器底层实现。读完本文,你将掌握.wasp文件中声明的书写规则、app/route/page等声明类型的使用方法、全部基础类型与领域类型,并能理解类型检查、Prisma 模型注入等编译原理,为从 Wasp DSL 平滑迁移到main.wasp.ts(TypeScript 配置)打下基础。

Wasp 语言是什么

Wasp 语言(即写在.wasp文件中的语言)是一门声明式(declarative)、静态类型(statically typed)的领域特定语言(DSL)。它并非通用编程语言,而是一门更接近 JSON、CSS 或 SQL 的配置语言——你不需要描述"如何做",只需要描述"要什么",其余的全栈复杂度(认证、后台任务、RPC、邮件发送、部署等)由 Wasp 编译器负责推导和生成。

用官方文档的原话说:"这门语言非常简单直观,没有太多需要学习的内容。"你完全可以边用边学,但如果想获得更形式化的定义和对它如何工作的更深理解,那么本文接下来的内容正是为你准备的。

提示(早期预览特性):如果你愿意,也可以不用main.wasp,而是选择用 TypeScript 来定义 Wasp 配置(main.wasp.ts)。详见 Wasp TypeScript 配置指南。本文讲解的是 Wasp 语言的 DSL 本体,而两种写法在语义上完全等价——理解 DSL 是理解 TS 配置 API 的最佳起点。

声明(Declarations):Wasp 语言的核心

Wasp 语言的中心概念是声明(declaration)。一段 Wasp 代码本质上就是一组声明,每一条声明描述你的 Web 应用的一个组成部分。

app MyApp { title: "My app" } route RootRoute { path: "/", to: DashboardPage } page DashboardPage { component: import { DashboardPage } from "@src/Dashboard.jsx" }

上面的例子用三条声明描述了一个 Web 应用:

  • app MyApp { ... }:声明应用本身,标题为 "My app";
  • route RootRoute { ... }:声明一条路由,路径/指向DashboardPage
  • page DashboardPage { ... }:声明一个页面,其 React 组件从@src/Dashboard.jsx导入。

声明的语法结构

书写一条声明的语法是:

<declaration_type> <declaration_name> <declaration_body>

其中:

组成部分含义说明
declaration_type声明类型Wasp 提供的声明类型之一,如approutepagequeryactionjobapicrud
declaration_name声明名称由你选择的标识符,用于命名这条声明
declaration_body声明体该声明的值/定义,必须匹配对应声明类型所期望的声明体类型

以上面的app声明为例:

  • 声明类型是app
  • 声明名称是MyApp(你也可以用任何其他标识符,比如foobarfoo_barhi3Ho);
  • 声明体是{ title: "My app" },即一个包含title字段、值为字符串的字典(dict),其类型与app声明类型所期望的声明体类型一致。

如果声明体类型不匹配,Wasp 编译器会直接报类型错误。例如把title改成little,因为这不匹配app声明体期望的类型,就会得到来自 Wasp 编译器的类型错误。

每一条声明背后都承载着含义,描述你的 Web 应用应当如何表现和运转。而 Wasp 语言中所有其他类型——原始类型(stringnumber)、复合类型(dictlist)、枚举类型(DbSystem)等——都是用来定义这些声明体的。

Wasp 类型系统全景

Wasp 的类型系统可以划分为两大类:基础类型(fundamental types)领域类型(domain types)

  • 基础类型是语言的基本积木,与其他主流语言中的类型非常相似;
  • 领域类型则是 Wasp 与众不同的地方,它们建模了 Web 应用的概念,如pageroutequery等。

这两类类型的权威定义分别位于编译器源码的 Type.hs(基础类型)与 StdTypeDefinitions.hs(领域类型)中。

基础类型

原始类型(Primitive Types)
类型示例说明
string"foo""they said: \"hi\""字符串字面量,支持转义
booltruefalse布尔值
number1214.5数字,支持整数与小数
declaration referenceTaskPageupdateTask对已存在声明的引用,直接写声明名称
ExtImport(外部导入)import Foo from "@src/bar.js"import { Smth } from "@src/a/b.js"src目录导入代码
json{=json { a: 5, b: ["hi"] } json=}用引号(quoter)包裹的 JSON 字面量

关于ExtImport有两条硬性规则:

  1. 路径必须以@src开头,其余部分相对于src目录解析;
  2. 导入必须是默认导入import Foo)或单个具名导入import { Foo })。

在编译器源码 ExtImport.hs 中可以看到,ExtImport实际由三部分组成:name(导入的是什么,区分默认导入ExtImportModule与具名导入ExtImportField)、path(从哪导入)以及可选的alias(在 Wasp 配置中的本地别名)。

复合类型(Composite Types)
类型示例说明
dict(字典){ a: 5, b: "foo" }键值对集合
list[1, 2, 3]列表
tuple(1, "bar")(2, 4, true)元组,只支持 2、3、4 元

在 Type.hs 的Type代数数据类型中,基础类型被建模为StringTypeNumberTypeBoolTypeExtImportTypeDictTypeListTypeTupleTypeQuoterType等构造子。值得注意的细节是:

  • EmptyListType:一个特殊类型,被临时赋给空列表,在typeCheck完成后所有该类型出现处都会被替换为合适的ListType
  • QuoterType tag:对应{=tag ... tag=}形式的引号语法(json 只是其中一个 tag);
  • 字典条目的必填/可选DictEntryType区分DictRequiredDictOptional(对应field:field?:),dictEntryRequired函数用于判定某条字段是否必须出现在声明体中。也就是说,声明体字典里的字段是可以声明为可选的。

领域类型(Domain Types)

领域类型定义在 StdTypeDefinitions.hs 的stdTypes集合中。从源码看,它通过TD.addDeclType/TD.addEnumType把以下类型逐一注册进类型定义表。

声明类型(Declaration Types)
声明类型含义
action写操作(修改数据)
api自定义 HTTP API
apiNamespaceAPI 命名空间
app应用本身
job后台任务
page页面
query读操作(查询数据)
route路由
crud自动生成的 CRUD 操作
枚举类型(Enum Types)
枚举合法值(依据当前仓库源码)
DbSystemPostgreSQLSQLite(见 Db.hs)
HttpMethodALLGETPOSTPUTDELETE(见 Api.hs)
JobExecutorPgBoss(见 Job.hs)
EmailProviderSMTPSendGridMailgunResendDummy(见 EmailSender.hs)

说明:以上枚举的合法取值以当前仓库源码为准,例如JobExecutor目前只有PgBoss一个构造子(其在FromJSON解析中只接受字符串"PgBoss");HttpMethod支持通配的ALL方法。

schema.prisma 中的模型(Models)

你可以在.wasp文件中直接引用schema.prisma文件中定义的模型,方式就是使用模型名,例如Task。这背后的机制值得展开:在编译器源码 Prisma.hs 中,parseEntityStatements会把 Prisma schema 中的每个模型解析为一条entity声明(以psl引号包裹模型体),并注入 Wasp 的 AST。也就是说,Prisma 模型与 Wasp 声明在编译期被统一到了同一条类型检查流水线上。

关于每种领域类型的声明体类型(body type)与语义细节,可查阅对应功能的文档页面(如认证、CRUD、Jobs、API 等)——例如api声明体包含fnentitieshttpRoute(方法 + 路径)、auth等字段,见 Api.hs;job声明体包含executorperform、可选的scheduleentities,见 Job.hs。

声明体类型是如何被定义与检查的

理解 Wasp 类型系统最直接的方式,是去看编译器如何把它落地。Wasp 编译器(Haskell 实现)中:

  1. 类型定义表TypeDefinitionsdeclTypes(声明类型)与enumTypes(枚举类型)两个映射构成,见 TypeDefinitions.hs。每个声明类型实际是一个 Haskell 记录类型(record),其字段即声明体字段,字段类型即字段期望的 Wasp 类型——例如App记录包含wasptitledeploymentheadauthserverclientdbemailSenderwebSocket等字段,见 App.hs;

  2. 类型检查typeCheck :: TypeDefinitions -> AST -> Either TypeError TypedAST,见 TypeChecker.hs。它对 AST 逐条检查是否符合 Wasp 类型规则,成功则产出携带类型标注的 AST,失败则返回TypeError——这就是前面提到的"把title改成little会报类型错误"的底层来源;

  3. 两种错误的区分:类型检查的错误与声明名称合法性的校验是分开的,StdTypeDefinitions.hs的注释特别提醒:新增声明类型时,必须在Wasp.AppSpec.Valid模块的validateUniqueDeclarationNames函数中同步更新,以检查重复的声明名。

这套设计把"语言定义"与"编译器逻辑"解耦:领域类型以数据驱动的方式注入 Analyzer,而不是硬编码,这让 Wasp 编译器/语言更容易扩展和维护。

从一个完整例子看三种声明的组合

把前面文档的示例扩展成一个更具实战感的组合,可以看到approutepage三种声明如何协作:

app MyApp { title: "My app" } route RootRoute { path: "/", to: DashboardPage } page DashboardPage { component: import { DashboardPage } from "@src/Dashboard.jsx" }

逐条拆解:

  • app MyApp声明体是一个字典,字段title的类型是string,这是app声明体类型要求的必填字段之一;
  • route RootRoute声明体包含pathstring)与to声明引用,指向一个page声明)两个字段;
  • page DashboardPage声明体的component字段类型是ExtImport,导入的路径@src/Dashboard.jsx@src开头、相对于src目录解析,且是默认导入。

这里to: DashboardPage正是声明引用(declaration reference)类型的用法——用声明名引用另一条声明,Wasp 编译器会在类型检查阶段验证被引用的声明确实存在且类型匹配。

与 Wasp TS 配置(main.wasp.ts)的对应关系

Wasp 0.15+ 提供了 Wasp TS config 作为.waspDSL 的替代方案:同样描述应用的高层结构(pages、routes、queries、actions、auth……),但用 TypeScript 书写,且是早期预览特性。从 DSL 迁移到main.wasp.ts的本质,是把每一条声明映射为App对象上的一个方法调用。

以仓库中真实的 examples/tutorials/TodoApp/main.wasp.ts 为例,前面的三条 DSL 声明在 TS 配置中等价于:

import { action, app, page, query, route } from "@wasp.sh/spec"; import { createTask, updateTask } from "./src/actions" with { type: "ref" }; import { LoginPage } from "./src/LoginPage" with { type: "ref" }; import { MainPage } from "./src/MainPage" with { type: "ref" }; import { getTasks } from "./src/queries" with { type: "ref" }; import { SignupPage } from "./src/SignupPage" with { type: "ref" }; export default app({ name: "TodoApp", wasp: { version: "0.26.0" }, title: "TodoApp", head: ["<link rel='icon' href='/favicon.ico' />"], auth: { userEntity: "User", methods: { usernameAndPassword: {}, }, onAuthFailedRedirectTo: "/login", }, spec: [ route("RootRoute", "/", page(MainPage, { authRequired: true })), route("SignupRoute", "/signup", page(SignupPage)), route("LoginRoute", "/login", page(LoginPage)), query(getTasks, { entities: ["Task"] }), action(createTask, { entities: ["Task"] }), action(updateTask, { entities: ["Task"] }), ], });

对照可见:

  • DSL 中的approutepagequeryaction在 TS 配置中对应同名函数;
  • 页面组件、查询/动作函数在 DSL 中用 ExtImport 描述,在 TS 配置中则直接以import ... with { type: "ref" }引入,语义一致;
  • 声明引用(to: DashboardPage)在 TS 配置中体现为把page(...)的返回值直接传给route(...)

理解 DSL 的类型系统后,你会更清楚地看到 TS 配置 API 背后的设计动机:每条声明就是一个类型化对象,字段类型与 DSL 声明体类型一一对应。完整的迁移步骤与参考文件可参阅 Wasp TypeScript 配置指南。

小结

  • Wasp 语言是声明式、静态类型的配置型 DSL,全部代码就是一组描述应用各个部分的声明
  • 声明语法为<declaration_type> <declaration_name> <declaration_body>,声明体类型必须与声明类型匹配,否则编译器报类型错误;
  • 类型系统分基础类型(string、bool、number、声明引用、ExtImport、json、dict、list、tuple)与领域类型actionapiapiNamespaceappjobpagequeryroutecrud等声明类型,以及DbSystemHttpMethodJobExecutorEmailProvider等枚举类型,外加schema.prisma中的模型引用);
  • 编译器的类型定义与检查逻辑分别位于 Type.hs、StdTypeDefinitions.hs、TypeChecker.hs,Prisma 模型通过 Prisma.hs 注入统一检查流水线;
  • 你可以选择继续使用main.waspDSL,也可以在 Wasp 0.15+ 中切换为等价的main.wasp.tsTypeScript 配置。

【免费下载链接】waspThe batteries-included full-stack framework for the AI era. Develop JS/TS web apps (React, Node.js, and Prisma) using declarative code that abstracts away complex full-stack features like auth, background jobs, RPC, email sending, end-to-end type safety, single-command deployment, and more.项目地址: https://gitcode.com/GitHub_Trending/wa/wasp

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询