前端进阶之旅前端进阶之旅
  • 基础篇HTML/CSS/JS 打底
  • 进阶篇原理与工程化
  • 高频篇面试最常问的那批
  • 精选篇按模块收敛的总结
  • 手写篇常考代码手写实现
  • 面经篇真实面试问题复盘
  • AI 篇NEWAI 时代的前端考点
  • 历年面经NEW按年份追踪真实考点
  • 每日一题每天一道,攒手感
  • 专项自测100 题快速查漏
  • 小程序题库小程序专项刷题
  • 算法题库NEW在线编码即时判题
  • 知识卡片NEW碎片时间过考点
  • 面试题大全常见问题解析
  • AI 答疑NEW随时提问,即时解析
  • AI 模拟面试NEW模拟真实面试 + 报告
  • AI 定制路线NEW按你的简历现排
  • AI 知识地图NEW串起全站知识点
  • 原理篇React / Vue 源码拆解
  • HTTP从报文一路讲到 HTTPS
  • 浏览器渲染、事件循环、进程
  • 计算机基础Linux、网络、操作系统
  • 设计模式23 种模式怎么用
  • Node学习指南从环境搭建到服务端
  • NPM工作流script、依赖与发布
  • Docker容器化部署上手
  • Canvas图形与动画实战
  • 前端系统进阶学习大型项目工程化
  • 前端综合文章长期沉淀的实践文
  • 思维导图知识点全景图
  • 学习路线按图索骥不跑偏
  • AI 热点NEWAI 每日动态
  • 公众号动态公众号历史文章
  • 博客动态站长的技术博客
  • 开发者导航常用工具与文档站
  • 基础篇HTML/CSS/JS 打底
  • 进阶篇原理与工程化
  • 高频篇面试最常问的那批
  • 精选篇按模块收敛的总结
  • 手写篇常考代码手写实现
  • 面经篇真实面试问题复盘
  • AI 篇NEWAI 时代的前端考点
  • 历年面经NEW按年份追踪真实考点
  • 每日一题每天一道,攒手感
  • 专项自测100 题快速查漏
  • 小程序题库小程序专项刷题
  • 算法题库NEW在线编码即时判题
  • 知识卡片NEW碎片时间过考点
  • 面试题大全常见问题解析
  • AI 答疑NEW随时提问,即时解析
  • AI 模拟面试NEW模拟真实面试 + 报告
  • AI 定制路线NEW按你的简历现排
  • AI 知识地图NEW串起全站知识点
  • 原理篇React / Vue 源码拆解
  • HTTP从报文一路讲到 HTTPS
  • 浏览器渲染、事件循环、进程
  • 计算机基础Linux、网络、操作系统
  • 设计模式23 种模式怎么用
  • Node学习指南从环境搭建到服务端
  • NPM工作流script、依赖与发布
  • Docker容器化部署上手
  • Canvas图形与动画实战
  • 前端系统进阶学习大型项目工程化
  • 前端综合文章长期沉淀的实践文
  • 思维导图知识点全景图
  • 学习路线按图索骥不跑偏
  • AI 热点NEWAI 每日动态
  • 公众号动态公众号历史文章
  • 博客动态站长的技术博客
  • 开发者导航常用工具与文档站
首页程序员面试题库GraphQL Non-Null 列表 nullability 语义
APAPI 设计GraphQL

GraphQL 中非空标记与列表组合(如 [User]、[User!]、[User]!)各自表示什么含义?

四种组合分别控制列表本身和列表元素是否可空:[User] 两者皆可空,[User!] 列表可空但元素非空,[User]! 列表非空但元素可空,[User!]! 两者皆非空。

前端进阶之旅 · 一题精讲更新于 2026.09.05
API 设计#GraphQL
先看核心答案
理解线索

非空标记位置决定作用对象

  1. 外置 !修饰列表字段,禁止返回 null 数组
  2. 内置 !修饰元素,禁止出现 null 元素
  3. 嵌套组合可同时声明,空列表仍有效

GraphQL 未提供非空列表约束,[] 对任何非空列表都是合法值。

核心回答

先记住这个答案

GraphQL 中 ! 修饰紧随其前的类型。[User] 表示字段返回 null 或 User 数组,数组元素可为 null;[User!] 表示数组可为 null,但每个元素非空;[User]! 表示数组必返回,但元素可为 null;[User!]! 表示数组和元素都不能为 null。若运行时元素为 null 而声明非空,会触发错误并冒泡至最近可空父字段,导致该字段整体为 null。

  • ! 放在列表外控制列表本身可空性
  • 放在列表内控制元素可空性
  • 非空元素为 null 会导致整个列表错误

非空标记的解析与错误冒泡

GraphQL 类型修饰符从右向左解析,[User!] 先声明元素非空,再声明列表本身可空;[User]! 则相反。当字段类型包含非空修饰时,若解析结果为 null,执行引擎会向父字段传播错误,并将该字段的返回值视为 null,但是否继续冒泡取决于父字段是否非空。

对于 [User!],若数组返回但某个元素为 null,则整个列表触发错误,且由于列表字段本身可空,该字段会变为 null,错误不会继续向上传播;只有当该字段本身声明为非空(如 [User!]!)时,错误才会继续向上一层传播。例如 friends: [User!] 中一个 null 元素导致 friends 整体为 null,只要 friends 本身可空,错误就不会影响其父对象。

设计好友列表字段的取舍

假设实现社交应用,用户 User 应有 friends 列表。业务要求好友列表始终返回数组,不允许为 null,但某个用户可能没有好友,用空数组表示。同时好友对象必须有 id 和 name,因此声明 friends: [User!]! 最合理。这样数组必存在,元素禁 null,空数组合法。

若误写成 friends: [User],则客户端可能收到 null 或含 null 的数组,迫使客户端防御式检查。若改为 friends: [User!],数组仍可能为 null,需要额外非空判断。通过组合 [User!]!,服务端强制保证返回数组且元素有效,客户端可安全迭代。

空列表与非空标记的边界情况

常见误解是 [User!]! 要求至少有一个元素,但 GraphQL 不提供此语法,空数组 [] 完全合法。若业务要求至少一项,必须自定义标量或使用额外字段如 totalCount,不能仅靠类型系统表达。

当数组内元素来自数据库关联查询时,若数据缺失导致某元素为 null,即使该字段声明为 [User!],整个列表也会变为 null,可能掩盖真实错误。为解决此问题,可在 resolver 中过滤 null 元素,或使用对象字段的非空约束并记录错误,避免整个列表失效。

回答前,多想一步

容易答错的地方

认为 `[User!]!` 不允许空数组
GraphQL 的 Non-Null 只禁止 null,不禁止空集合。[] 是合法返回值,不要依赖类型系统保证非空列表。
混淆列表可空与元素可空
[User]! 允许元素为 null,但列表必须存在。若业务要求元素也非空,必须写成 [User!]!,否则客户端需处理 null 元素。
试着用自己的话回答

面试官还会怎么问?

当 `[User!]` 中的某个元素为 null,实际响应中整个字段是 null 还是只该元素为 null?

整个列表字段会变为 null,因为非空元素被破坏导致列表字段错误,且该字段本身可空,所以错误传播后字段整体为 null,同时 errors 数组会记录详情。

如何在 schema 中声明一个必含至少一个元素的数组?

GraphQL 类型系统不提供此能力。可用自定义标量或在 resolver 中校验,若不符合规则则抛出错误,使得字段返回 null 并触发错误。

非空列表嵌套非空,如 `[[User!]]!` 含义是什么?

外层列表非空,内层列表可空但元素非空。即必须返回数组,数组中每个子列表可为 null,但子列表内元素不能为 null。

从一道题,走向一组知识

把知识连起来

GraphQL

GraphQL 中 Enum 适合建模什么,哪些情况应避免使用 Enum?

同属「GraphQL」专题,接着看 GraphQL enum 适用场景 演进 在具体场景中的处理方式。

GraphQL

GraphQL 的 Interface 与 Union 类型在语义和使用场景上有什么区别?

同属「GraphQL」专题,接着看 GraphQL interface union 区别 在具体场景中的处理方式。

参考资料

  • Schemas and Types

示例用于理解所注明的运行环境与边界;延伸学习可结合原文中的更多案例。

本题目录
  1. 先记住这个答案
  2. 非空标记的解析与错误冒泡
  3. 设计好友列表字段的取舍
  4. 空列表与非空标记的边界情况
  5. 容易答错的地方
  6. 面试官还会怎么问
  7. 把知识连起来
读懂,再试着讲出来

先看核心答案,再读代码。最后展开追问,检查自己有没有遗漏边界。

试着回答追问
浏览全部面试题理解原理,也关注真实的使用场景。回到顶部 ↑