导读:本期聚焦于柬埔寨程序员创作的《如何用TypeScript为DOSH封装符合西班牙无障碍法令的表单错误提示类型?》,敬请观看详情。表单验证失败后只把错误信息放在颜色变化上,屏幕阅读器用户根本不知道哪里出错,这恰好是西班牙无障碍法令重点约束的场景。DOSH项目在接入公共部门表单时需要对错误提示做结构化封装。本文直接给出一种用TypeScript定义错误提示联合类型、错误优先级、关联字段与ARIA映射的实现方案,并说明如何避免把错误信息散落在组件内部。通过ErrorHint类型与验证器返回结果的组合,可以让每个表单控件在出错时自动获得role=alert或aria-describedby,减少无障碍审计中的常见扣分点。文章还覆盖错误码国际化与测试策略,适合需要同时满足西语和加泰罗尼亚语场景的表单工程。

在西班牙公共部门数字化项目里,表单错误提示的合规处理经常被简化成“变红加文字”,但无障碍审计并不认可这种做法。根据西班牙皇家法令 Real Decreto 1112/2018 所引用的 EN 301 549 标准,公共部门网站与移动应用必须让残障用户能够感知、理解并修正输入错误。DOSH 作为团队内部使用的表单渲染库,如果错误提示类型设计得过于松散,各业务模块就会用字符串、布尔值或任意对象传递错误状态,最后导致读屏软件无法稳定播报错误摘要。本文的目标就是把这类提示统一成可推导、可测试的 TypeScript 类型,并接入无障碍属性映射。

如何用TypeScript为DOSH封装符合西班牙无障碍法令的表单错误提示类型?

西班牙无障碍法令对错误提示的约束不只在颜色上

很多前端团队对 WCAG 的理解停留在对比度层面,认为错误提示只要有红色边框和一段说明文字就足够了。但 EN 301 549 对表单错误的要求要具体得多。按照 WCAG 2.1 的 3.3.1 错误识别,如果输入错误能够被自动检测,就必须用文本方式指出出错的项目。3.3.3 错误建议进一步要求,在已知修正方式时向用户提供建议,除非这样做会危及安全或改变内容含义。4.1.3 状态消息则强调,动态出现的错误信息需要被辅助技术及时感知,不能只靠视觉变化。

也就是说,一个合规的错误提示至少需要回答三个问题:哪个字段出错了、错误原因是什么、用户应该怎么改。颜色、图标、边框都只能作为辅助线索,不能单独承担错误提示的职责。对于 DOSH 这类承载多个政府表单的库来说,同一套错误提示必须能映射到 aria-invalid、aria-describedby 以及具有 role="alert" 或 aria-live 的容器上。否则每次做无障碍审计,都会因为错误提示与控件没有关联而被扣分。

还有一个容易忽略的点:错误提示不应在页面加载时就静默存在,也不应在用户修正后仍然保留。理想状态是,当验证失败时,错误信息动态插入并触发播报;当用户填写正确时,错误状态被清除,同时辅助技术能感知到状态消失。因此类型设计中需要区分错误的严重级别和生命周期,而不是仅仅用一个布尔值表示有无错误。

用 TypeScript 定义可扩展的错误提示类型

为了让 DOSH 中的表单错误提示可复用,第一步是定义错误级别和错误提示实体。错误级别不能只用一个 boolean,因为“必填项为空”和“格式可能有误但允许保存草稿”的风险完全不同。一个实用的方案是使用字符串字面量联合类型,既能获得编译期检查,又能在运行时保持简单。下面是一个基础类型示例:

type ErrorSeverity = 'error' | 'warning' | 'info';

interface ErrorHint {
  /** 错误关联的表单控件 id,必须与真实控件的 id 一致 */
  fieldId: string;
  /** 面向用户的可读错误消息,可由翻译模块替换 */
  message: string;
  /** 错误级别,决定 aria-invalid 与通知策略 */
  severity: ErrorSeverity;
  /** 可选的修正建议,例如格式示例或长度限制 */
  suggestion?: string;
  /** 机器可读的错误码,便于测试与 i18n 查表 */
  code: string;
}

type ValidationResult =
  | { valid: true; value: string }
  | { valid: false; errors: ErrorHint[] };

ErrorHint 的核心是 fieldId 和 code,前者负责与具体控件绑定,后者负责翻译和测试。为什么 errors 要用数组而不是单个对象?因为一个字段可能同时命中多条规则,比如输入了过短的值并且包含非法字符,此时用户需要一次看到或听到所有需要修正的点,而不是处理完一条再看到另一条。允许数组也能让验证器按规则顺序返回错误,后续在错误摘要中按优先级排序。

仅定义实体还不够,DOSH 还需要统一的构造器,避免业务代码手动拼接错误对象。下面这个工厂函数把字段 id、错误码、默认文案和级别打包起来,让调用方不必关心完整结构:

function buildErrorHint(
  fieldId: string,
  code: string,
  message: string,
  severity: ErrorSeverity = 'error'
): ErrorHint {
  return { fieldId, code, message, severity };
}

这样做的好处是,后续如果要在错误对象上增加 focusTarget 或 liveRegionId,只需要改工厂函数和接口定义,所有调用方不受影响。同时,ValidationResult 的联合类型让验证器返回值只有成功和失败两种形态,成功时携带规范化后的值,失败时携带错误数组。组件层在使用结果时可以依靠 TypeScript 的收窄能力,不必再做 if (result.errors) 这类脆弱的运行期判断。

在 DOSH 表单渲染层接入无障碍映射

类型定义之后,最关键的是把它映射到无障碍属性。DOSH 的文本输入组件可以接收 ErrorHint[],然后根据错误级别计算 aria-invalid,并给每个错误提示生成唯一 id,再把这些 id 通过 aria-describedby 关联到控件上。错误提示本身需要根据级别渲染为 role="alert" 或 role="status",这样动态插入时读屏软件能立即播报。

import { ErrorHint } from './error-types';

interface TextFieldProps {
  id: string;
  label: string;
  errors: ErrorHint[];
}

export function TextField({ id, label, errors }: TextFieldProps) {
  const hasError = errors.some(e => e.severity === 'error');
  const errorIds = errors.map(e => `${id}-${e.code}`);
  return (
    <div className="field">
      <label htmlFor={id}>{label}</label>
      <input
        id={id}
        aria-invalid={hasError}
        aria-describedby={errorIds.join(' ')}
      />
      {errors.map((error, index) => (
        <p
          key={error.code}
          id={errorIds[index]}
          className="field-error"
          role={error.severity === 'error' ? 'alert' : 'status'}
        >
          {error.message}
          {error.suggestion ? `,${error.suggestion}` : ''}
        </p>
      ))}
    </div>
  );
}

这段代码没有在高阶组件里隐藏错误渲染逻辑,而是把 errors 作为显式数据流传入。这样视觉错误文本和 aria-describedby 指向的内容天然一致,不会出现页面上写“NIF 格式错误”而读屏却读到“字段无效”的情况。需要注意,role="alert" 适合严重错误,会打断当前读屏;role="status" 适合警告或提示,不会打断。使用 severity 区分二者比在组件里写死更合理。

除了单字段错误,DOSH 还应在提交失败时生成错误摘要。错误摘要通常放在表单顶部,集中列出所有 severity === 'error' 的提示,并设置 role="alert" 或 aria-live="assertive"。摘要中的每一项可以点击或直接跳转到对应字段,但跳转逻辑不必写在类型层,组件根据 fieldId 调用 document.getElementById 即可。焦点管理是另一个无障碍重点:提交失败后把焦点移到第一个出错控件,能显著减少键盘和读屏用户的操作路径。

错误提示的国际化与测试策略

西班牙公共部门的表单不仅要提供西班牙语,还经常需要加泰罗尼亚语、巴斯克语或加利西亚语。把用户可见文案直接写死在验证器里会带来巨大的维护成本。更稳妥的做法是让 ErrorHint 只携带错误码,渲染层根据当前语言解析消息。错误码使用枚举或字面量联合,配合一个记录类型完成翻译映射。下面是一个支持西班牙语和加泰罗尼亚语的示例:

type ErrorCode = 'REQUIRED' | 'FORMAT_NIF' | 'MAX_LENGTH';

const errorMessages: Record<ErrorCode, { es: string; ca: string }> = {
  REQUIRED: { es: 'Este campo es obligatorio.', ca: 'Aquest camp és obligatori.' },
  FORMAT_NIF: { es: 'El formato del NIF no es válido.', ca: 'El format del NIF no és vàlid.' },
  MAX_LENGTH: { es: 'Has superado la longitud máxima.', ca: 'Has superat la longitud màxima.' },
};

有了稳定的错误码,单元测试就不再需要依赖本地化文案。测试可以断言某个验证器在空值输入时返回 { code: 'REQUIRED', severity: 'error' },而不必担心西语重音符号或大小写变化。另一方面,类型守卫函数可以作为运行时保障,防止后端返回的异常数据被塞进错误列表。比如一个 isErrorHint 守卫会检查 fieldId、message、severity 和 code 是否都存在且类型正确。

对无障碍映射的测试同样不能忽略。可以围绕渲染函数做三组检查:第一,当 errors 包含 severity: 'error' 时,输入框必须具有 aria-invalid="true";第二,每个错误提示元素必须有 id,且这些 id 全部出现在输入框的 aria-describedby 中;第三,动态插入的错误容器必须具有 role="alert" 或等效的 aria-live 属性。把这些检查固化到 CI,可以避免后续功能迭代破坏无障碍支持。

常见实现误区与避坑清单

即便理解了规范,实际封装时仍会出现几类典型问题。最常见的是只用颜色变化提示错误,没有文本说明。第二类是错误信息与输入框缺少程序化关联,读屏用户聚焦到控件时听不到错误描述。第三类是把错误信息放在 placeholder 或 title 属性里,这些属性不能被稳定播报,也不适合承载需要用户记住的修正建议。第四类是动态插入错误提示时没有设置 role="alert",导致读屏软件完全忽略新出现的错误节点。

还有一类隐蔽问题来自错误状态清理。用户修正字段后,如果只把错误文字隐藏而不更新 aria-invalid 和 aria-describedby,读屏软件仍会认为该字段处于错误状态。DOSH 应在每次输入或失焦验证时同步更新错误数组,而不是依赖 CSS 显隐。使用受控组件时,可以结合 useState 或表单状态管理库把 ErrorHint[] 作为唯一错误来源,视觉渲染和无障碍渲染都从这一来源派生。

下面是一个可以作为收尾自检的清单:错误提示是否都通过 ErrorHint 结构生成;每个严重错误是否同时关联到控件和顶部摘要;错误容器是否具有正确的 role;提交失败后焦点是否移动到首个错误字段;错误码是否覆盖了需要的语言;运行时是否用类型守卫拦截非法数据。把这些条目纳入组件评审,西班牙无障碍法令就不再是上线前的突击修补,而是从一开始就融入 DOSH 的表单渲染流程。

TypeScript表单无障碍DOSH修改时间:2026-10-04 15:37:03

免责声明:已尽一切努力确保本网站所含信息的准确性。网站作品多为原创整理与精心创作,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们进行处理Email:chomcom@qq.com。
引用或转载本作品时,请注明当前出处:https://www.ipipp.com/html/1004/65609.html,基于非商业用途的前提下,欢迎转载或二创本作品。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。