导读:本期聚焦于俊华创作的《如何用TypeScript为IWAC封装波兰网络无障碍指南的非文本内容类型定义?》,敬请观看详情。IWAC在做无障碍审计时经常遇到非文本内容检查逻辑分散、字段含义模糊的问题。波兰网络无障碍指南要求所有非文本元素要么提供等效文本,要么明确标记为装饰或需要扩展描述。直接把规则写在运行时校验函数里会导致类型与规则脱节。本文用TypeScript为IWAC封装一套非文本内容类型定义,从图像、图标、音频、视频四个维度建立判别联合类型,把替代文本、字幕轨道、描述文本、装饰标记等字段编译期可校验。通过类型守卫和穷尽检查,确保每一种媒体类型都能落到无障碍规则分支中,避免遗漏。文章还给出与ARIA属性映射的接口设计思路,以及如何把类型定义拆分为可维护的模块。

波兰网络无障碍指南把非文本内容当成一个独立审计域,而不是简单检查alt属性。IWAC在实现这些规则时,首先要解决类型定义问题。如果每个开发者都按自己的理解给图像、图标、音频、视频添加字段,运行时校验就会变成一坨难以维护的if。TypeScript的判别联合可以从编译期把不同媒体类型拆开,再配合穷尽检查保证每条规则都对应到具体分支。接下来从指南中的非文本分类谈起。

如何用TypeScript为IWAC封装波兰网络无障碍指南的非文本内容类型定义?

一、波兰网络无障碍指南对非文本内容的约束

指南要求审计工具能区分四类非文本元素:传达信息的图像、功能性图标、纯装饰元素、多媒体内容。它们在替代文本、隐藏标记、字幕和描述方面的要求完全不一样。举例来说,信息图像必须有非空alt或等效长描述;装饰元素反而不能给任何可被读屏识别的文本,需要aria-hidden或role=presentation;图标如果参与交互,就必须提供可访问名称,而不是alt。

如果用传统的interface NonTextContent { alt?: string }来表示,装饰元素和缺失字段就会混淆。空字符串alt在语义上是“故意装饰”,undefined却是“检查项缺失”。这两个状态在波兰指南中对应完全不同的处理逻辑。音频和视频更是没法用alt覆盖,它们需要transcript、captions、audioDescription等独立字段。

所以对IWAC来说,非文本内容不是一种类型,而是一组类型的集合。下面用一段对比说明:

  • 信息图像:alt必填,允许longDescription。
  • 装饰图像:alt必须为空字符串,ariaHidden为真。
  • 功能性图标:无alt,但accessibleName必填。
  • 音频:transcript必填,captions可选。
  • 视频:transcript、captions必填,audioDescription可选。

这种分类如果不进类型系统,只能靠运行时写switch一类一变。但TS可以提前约束。下面给出类型建模。

二、用判别联合封装非文本内容类型

先定义基础接口,把公有的id、source、guidelineRef放进去。然后每个类型扩展基础接口,并用type字段标出唯一字面量。注意装饰图像的空字符串并不是“缺少值”,而是有效值。代码:

interface BaseNonTextContent {
  id: string;
  source: string;
  /** 对应波兰网络无障碍指南条款编号 */
  guidelineRef?: string;
}

interface InformativeImage extends BaseNonTextContent {
  type: 'informative-image';
  alt: string;
  longDescription?: string;
}

interface DecorativeGraphic extends BaseNonTextContent {
  type: 'decorative-graphic';
  alt: '';
  ariaHidden: true;
}

interface FunctionalIcon extends BaseNonTextContent {
  type: 'functional-icon';
  accessibleName: string;
  iconRole: 'img' | 'button' | 'link';
}

interface AudioContent extends BaseNonTextContent {
  type: 'audio';
  transcript: string;
  captions?: string[];
}

interface VideoContent extends BaseNonTextContent {
  type: 'video';
  transcript: string;
  captions: string[];
  audioDescription?: string;
  signLanguage?: boolean;
}

上面代码中type是判别字段,InformativeImage等必须通过类型守卫才能访问各自独有字段。接着将五个接口合成联合类型:

type NonTextContent =
  | InformativeImage
  | DecorativeGraphic
  | FunctionalIcon
  | AudioContent
  | VideoContent;

联合类型的好处是,当你拿到NonTextContent后访问content.alt,TS会报错,因为不是所有成员都有alt。这迫使你在访问前先收窄类型。与用可选字段相比,这种设计把“哪些类型有alt、哪些必须用accessibleName”都编码进了编译期。坏处是类型声明变长,新增媒体类型时需要同步更新联合、校验函数和映射函数。

三、类型守卫与穷尽检查驱动规则落地

类型定义只是第一步,真正执行波兰指南规则要靠类型守卫和穷尽检查。写一个校验函数,在switch中按type分支检查必填字段是否有效。对于装饰图形,需要同时满足alt为空和ariaHidden为真,这里用逻辑与需转义。代码:

function assertNonTextAccessibility(content: NonTextContent): boolean {
  switch (content.type) {
    case 'informative-image':
      return content.alt.trim().length !== 0;
    case 'decorative-graphic':
      return content.alt === '' && content.ariaHidden === true;
    case 'functional-icon':
      return content.accessibleName.trim().length !== 0;
    case 'audio':
      return content.transcript.trim().length !== 0;
    case 'video':
      return content.transcript.trim().length !== 0 && content.captions.length !== 0;
    default: {
      const exhaustive: never = content;
      throw new Error('未处理的非文本类型: ' + exhaustive);
    }
  }
}

default分支用never做穷尽检查。以后如果往NonTextContent里加了CanvasChart或DataTable类型,却没有在switch中处理,编译会直接报错。这比运行时发现漏检强得多。

再补充一个类型守卫,用于从unknown输入中提取非文本内容。实际IWAC从JSON或DOM解析出来的数据都是unknown,不能直接假定为NonTextContent。需要先检查基础形状。代码:

function isDecorative(content: NonTextContent): content is DecorativeGraphic {
  return content.type === 'decorative-graphic';
}

function parseNonTextContent(raw: unknown): NonTextContent | null {
  if (typeof raw !== 'object' || raw === null) return null;
  const candidate = raw as { type?: unknown };
  if (typeof candidate.type !== 'string') return null;
  return candidate as NonTextContent;
}

isDecorative返回类型谓词,调用方在if块内拿到的就是DecorativeGraphic,可以安全访问ariaHidden。不建议用as强制断言,因为一旦来源数据格式变化,强转会掩盖错误。

四、ARIA映射与模块化组织

非文本内容最终要渲染到DOM或生成审计报告,需要映射为aria-label、aria-hidden、role、alt等属性。可以定义一个A11yProps接口,并让toA11yProps统一处理。这样渲染层不关心具体类型,只消费生成好的属性。代码:

interface A11yProps {
  'aria-label'?: string;
  'aria-hidden'?: boolean;
  role?: string;
  alt?: string;
}

function toA11yProps(content: NonTextContent): A11yProps {
  switch (content.type) {
    case 'informative-image':
      return { alt: content.alt, role: 'img' };
    case 'decorative-graphic':
      return { alt: '', 'aria-hidden': true, role: 'presentation' };
    case 'functional-icon':
      return { 'aria-label': content.accessibleName, role: content.iconRole };
    case 'audio':
      return { 'aria-label': '音频内容' };
    case 'video':
      return { 'aria-label': '视频内容' };
    default: {
      const exhaustive: never = content;
      return exhaustive;
    }
  }
}

在IWAC仓库中,建议把类型定义放在types/media.ts,类型守卫放在guards/media.ts,ARIA映射放在mappers/a11y.ts。不要把全部类型塞进单个index.ts,否则后续加类型时会互相影响。

类型定义和指南版本要保持同步。可以在注释里写明对应的波兰指南条款编号,这样每次指南更新时,开发者能快速定位需要修改的接口。这套体系的最终目标不是单纯通过类型检查,而是让无障碍规则从口口相传变成编译器可验证的契约。

以上从指南分类、类型建模、校验收窄到ARIA映射,用TypeScript为IWAC封装非文本内容类型定义。这样审计模块不再靠散落的字符串判断,每条非文本规则都落到具体联合成员上。

TypeScriptIWAC非文本内容类型修改时间:2026-09-25 15:27:03

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