Elixir v1.20 发布成渐进式类型语言类型系统升级且编译时间再改进2026 年 6 月 3 日José Valim 宣布 Elixir v1.20 发布Elixir 现已成为渐进式类型语言。早在 2022 年团队就宣布了为 Elixir 添加集合论类型的计划。2023 年 6 月发表了关于 Elixir 类型系统设计的获奖论文并表示工作从研究阶段过渡到开发阶段。随着 Elixir v1.20 发布完成了第一个开发里程碑无需引入类型注解就能对每个 Elixir 程序进行类型推断和渐进式类型检查。这让 Elixir 能检测出死代码和“已验证的错误”可高效在现有程序中发现问题不给开发者增加额外负担误报率极低。在此次公告中将详细介绍类型系统的目标、dynamic() 类型的含义以及它发现“已验证的错误”的方式。Elixir 在 “If T: 类型缩小基准测试” 中表现出色通过了 13 个类别中的 12 个能从普通代码中恢复精确类型信息发现已验证的错误。这个类型系统的实现得益于 CNRS 和 Remote 的合作目前开发工作由 Fresha 和 Tidewave 赞助。Elixir 里也有类型了团队目标是引入具备以下特性的类型系统可靠性类型系统推断和分配的类型与程序行为一致。渐进性包含 dynamic() 类型运行时检查变量或表达式类型时可用。不使用 dynamic()类型系统就像静态类型系统一样工作。开发者友好用基本集合操作描述、实现和组合类型有清晰错误信息。在现有语言中引入类型系统是复杂变革第一个里程碑是不引入类型注解实现类型系统通过 dynamic() 类型为开发者发现死代码和已验证的错误提供价值。dynamic() 类型许多渐进式类型系统有 any() 类型意味着“一切皆可”不报告类型违规。而 Elixir 的 dynamic() 类型有兼容性和缩小性两个重要特性。在静态类型系统中integer() or binary() 类型变量调用函数时函数需接受这两种类型可能导致误报。例如def percentage_or_error(value) when is_integer(value) do value_or_error if value 1 do value else not well end # ... 更多代码 ... if value 1 do value_or_error / 100 else String.upcase(value_or_error) endend虽然 value_or_error 类型是 integer() or binary()但 / 运算符只接受数字String.upcase 只接受二进制/字符串程序有效且运行时不抛异常但类型系统会报告两个违规。为避免过多误报削弱开发者对类型系统的信任Elixir 的渐进式类型系统将 value_or_error 标记为 dynamic(integer() or binary()) 类型意味着运行时要么是 integer()要么是 binary()。调用函数时只有提供的类型和接受的类型不相交才会发出类型违规。若将程序修改为value_or_error if value 1 do value else not well endMap.fetch!(value_or_error, :some_key)因为 Map.fetch! 期望映射数据结构而 value_or_error 运行时只能是整数或二进制提供的类型和接受的类型不相交会导致类型违规这就是兼容性特性。为解决只报告已验证错误但找不到很多错误的问题Elixir 的动态类型可缩小。例如def add_a_and_b(data) do data.a data.benddata 最初是 dynamic() 类型使用 data.a 和 data.b 后Elixir 会将 data 类型细化为 %{..., a: number(), b: number()}。若写成def add_a_and_b(data) do data.a dataenddata 先被缩小为 %{..., a: number()} 类型的映射再用作 number() 类型会发出类型违规。Elixir 中的 dynamic() 类型像范围程序执行中可细化类型检查超出范围就报告违规与其他渐进式类型系统不同。实际上类型推断和类型检查算法就像将所有参数类型注解为 dynamic() 一样。引入用户提供的类型注解不使用 dynamic()Elixir 的类型系统就像静态类型语言一样工作。跨越静态和动态边界时开发了新技术确保渐进式类型的可靠性无需额外运行时检查。类型守卫、子句等本次发布为多个结构引入类型检查和缩小功能。守卫可推断并集、交集和补集。例如def example(x, y) when is_list(x) and is_integer(y)推断出 x 是列表y 是整数。def example({:ok, x} y) when is_binary(x) or is_integer(x)推断出 x 是二进制或整数y 是二元元组第一个元素是 :ok第二个元素是二进制或整数。def example(x) when is_map_key(x, :foo)推断出 x 是包含 :foo 键的映射用 %{..., foo: dynamic()} 表示。def example(x) when not is_map_key(x, :foo)推断出 x 是不包含 :foo 键的映射类型为 %{..., foo: not_set()}访问 x.foo 会引发类型违规。还可对数据结构大小进行断言如def example(x) when tuple_size(x) 3Elixir 跟踪到元组最多有两个元素访问 elem(x, 3) 会发出类型违规。对于映射和列表将大小检查转换为空检查。case 和条件语句Elixir 利用前面子句信息细化后续子句。例如case System.get_env(SOME_VAR) do nil - :not_found value - {:ok, String.upcase(value)}endSystem.get_env(SOME_VAR) 返回 nil 或 binary()第一个子句匹配 nil类型系统知道 value 只能是 binary()第二个子句能通过类型检查。跨子句的类型缩小有助于发现冗余子句和死代码。此外对标准库中许多处理元组和映射的函数进行了类型标注更多详细信息可在 [发布说明](https://github.com/elixir-lang/elixir/releases/tag/v1.20.0) 中找到。编译时间改进Elixir v1.20 改进了编译时间特别是在多核机器上运行的应用程序。综合基准测试表明Elixir 的构建工具是 BEAM 语言中最快的。若想提供更多示例和场景可发起讨论以便提供透明的基准测试和结果。它还引入了新的编译器选项 :module_definition用于指定模块定义是 :compiled默认还是 :interpreted可能提高大型项目的编译时间不影响 .beam 文件只影响 defmodule 内部内容的执行方式。可在 mix.exs 中设置 elixirc_options: [module_definition: :interpreted] 启用[阅读文档以了解更多信息](https://elixir.hexdocs.pm/1.20.0/Code.html#put_compiler_option/2)。下一步计划团队面临的最大问题是 Elixir 何时引入利用集合论类型的新类型签名。如在 2026 年 ElixirConf EU 主题演讲中讨论的还有研究和开发工作要做。只会在以下条件满足时引入类型签名对 Elixir v1.20 中类型系统的性能满意已广泛优化改进。能够高效实现递归类型。能够高效实现参数化类型。能够高效将映射的键值对作为可枚举对象进行遍历仍在研究可能的解决方案。解决这些问题后将探索和讨论类型化的结构体定义最终实现类型签名。会通过新闻和 [Elixir 论坛](https://elixirforum.com/) 向社区通报进展。感谢所有试用候选版本、运行基准测试并反馈的人不妨试试 Elixir v1.20修复它免费发现的所有错误新闻[Elixir v1.20 发布](https://elixir-lang.org/blog/2026/06/03/elixir-v1-20-0-released/)博客分类[公告](https://elixir-lang.org/blog/categories.html#Announcements)[生产环境中的 Elixir](https://elixir-lang.org/cases.html)[内部机制](https://elixir-lang.org/blog/categories.html#Internals)[版本发布](https://elixir-lang.org/blog/categories.html#Releases)重要链接[开发与团队](https://elixir-lang.org/development.html)[源代码与问题跟踪](https://github.com/elixir-lang/elixir)[观看 Elixir 迷你纪录片](https://www.youtube.com/watch?vlxYFOM3UJzo)加入社区[Hex.pm 包管理器](https://hex.pm)[Twitter 上的 elixirlang](https://twitter.com/elixirlang)[irc.libera.chat 上的 #elixir](irc://irc.libera.chat/elixir)[Elixir 论坛](https://elixirforum.com)[Elixir 的 Slack 社区](https://elixir-lang.slack.com/join/shared_invite/zt-eivteker-k_nArD59XHjjN_r8qeH6dw#/shared-invite/email)[Elixir 的 Discord 社区](https://discord.gg/elixir)[IDE/编辑器支持](https://github.com/elixir-lang/elixir/wiki/Code-Editor-Support)[全球聚会活动](https://www.meetup.com/topics/elixir/)[工作与招聘社区维基](https://github.com/elixir-lang/elixir/wiki/Hiring-Elixir-Developers)[活动与资源社区维基](https://github.com/elixir-lang/elixir/wiki)[加入 Erlang 生态系统基金会](https://erlef.org/ 加入 Erlang 生态系统基金会)