导读:本期聚焦于永濑创作的《如何在TypeScript中定义Web OTP API短信验证码自动填充的数据类型》,敬请观看详情。短信验证码自动填充功能用起来很便捷,但在 TypeScript 里一调用 navigator.credentials.get 就提示类型错误,于是有人直接用 any 草草处理。本文从 Credential Management API 与 Web OTP 规范的关系入手,说明为什么标准库 lib.dom.d.ts 中缺少 OTPCredential 类型,并给出两类补全方案:通过声明合并扩展 CredentialRequestOptions 的 otp 参数,以及定义继承 Credential 的 OTPCredential 接口配合类型守卫使用。还会演示如何结合 AbortController 封装带超时的验证码获取函数,并梳理短信格式与浏览器兼容的注意点。读完可以彻底移除 any,让验证码自动填充逻辑在编辑器里获得完整类型检查与代码提示。

在 TypeScript 项目中使用 Web OTP API 实现短信验证码自动填充时,很多开发者会碰到一个尴尬的情况:调用 navigator.credentials.get 传入 otp 参数时,编译器直接报错,提示 CredentialRequestOptions 类型上不存在 otp 属性。即便通过类型断言绕过了参数检查,返回的 credential 对象也被推断为基础 Credential 类型,无法直接访问验证码字段。造成这种现象的原因是 TypeScript 内置的 lib.dom.d.ts 尚未完整收录 Web OTP 规范中定义的数据类型。接下来我们结合规范与工程实践,把缺失的类型补全,让验证码自动填充逻辑具备完整的类型安全保障。

如何在TypeScript中定义Web OTP API短信验证码自动填充的数据类型

一、Web OTP API 属于哪一套标准,类型缺失从何而来

Web OTP API 是 Credential Management API 的一个扩展,由 W3C Web Incubator Community Group 提出,目标是让浏览器能够从短信中自动提取一次性验证码并填充到表单。规范里定义了 OTPCredential 接口,该接口继承自 Credential,额外包含一个 code 字符串属性。当网页调用 navigator.credentials.get({ otp: { transport: ['sms'] } }) 时,浏览器会监听符合格式的短信,并在用户授权后解析出验证码。

然而,TypeScript 官方维护的 lib.dom.d.ts 文件更新速度并不总是跟上浏览器的实验性特性。在不少 TypeScript 版本中,CredentialRequestOptions 接口里没有 otp 字段,同时也没有独立的 OTPCredential 类型。这就导致开发者要么使用类型断言绕过检查,要么默默接受 any,失去了类型系统应有的保障。如果项目开启了 strict 模式,这类问题会更加突出,因为 any 和未知属性会引发连锁报错。

为了解决这个问题,可以利用 TypeScript 的声明合并机制,在项目的类型声明文件里为已有接口补充属性,或者定义独立的 OTPCredential 接口并按需断言。两种方式各有适用场景,接下来分别说明。

二、给 CredentialRequestOptions 补上 otp 参数类型

navigator.credentials.get 方法的参数类型是 CredentialRequestOptions。标准接口定义中只包含 password、federated、publicKey 等字段,并没有 otp。因此,要传递短信验证码请求参数,必须扩展这个接口。TypeScript 允许在全局作用域中重新打开已经存在的接口,并添加新的可选属性。

具体做法是创建一个 .d.ts 文件,使用 declare global 和 interface 合并。示例代码如下:

declare global {
  interface CredentialRequestOptions {
    otp?: {
      transport?: Array<'sms'>;
    };
  }
}

export {};

上面的代码里 transport 被定义为只包含 'sms' 的字符串字面量数组,这是因为 Web OTP 目前仅支持短信通道。写成可选属性是为了兼容那些不支持该特性的环境,避免运行时出现意外。注意 export {} 是必需的,它让这个文件被当作模块处理,从而允许 declare global 生效。如果你的项目已经使用了 import 或 export 语句,这个空导出可以省略。

三、定义 OTPCredential 接口并实现类型守卫

扩展请求参数后,返回值的类型仍然不够精确。navigator.credentials.get 默认返回基础 Credential 或 null,而基础 Credential 接口只有 id、type 等通用字段,并不包含 code。需要定义一个 OTPCredential 接口,让它继承 Credential 并追加 code 属性,然后在使用时进行类型收窄。

先给出接口定义和类型守卫函数的代码:

interface OTPCredential extends Credential {
  code: string;
}

function isOTPCredential(credential: Credential | null): credential is OTPCredential {
  return credential !== null && credential.type === 'otp' && typeof (credential as any).code === 'string';
}

类型守卫 isOTPCredential 返回 credential is OTPCredential,这意味着当函数返回 true 时,TypeScript 会将 credential 变量收窄为 OTPCredential 类型。在条件判断内部,可以直接访问 credential.code,编译器会认为它是 string 类型。函数体中使用了 as any 断言来读取 code 属性,因为基础 Credential 类型并没有这个字段。如果不想使用 any,也可以先用 in 运算符检查 'code' in credential,但那样需要额外的类型处理。这里的实现兼顾了简洁和可读性。

四、封装请求函数并处理超时与错误

有了类型定义和守卫,就可以封装一个完整的获取验证码函数。实际业务中,短信验证码通常有有效期,而且浏览器监听短信的行为不能一直持续,否则会消耗资源。Web OTP API 支持通过 AbortController 终止获取操作,可以配合 setTimeout 实现超时控制。

下面是封装后的代码,它返回一个 Promise,解析结果为验证码字符串。如果用户取消或超时,则抛出对应错误。

async function getOTPCode(timeoutMs: number = 60000): Promise<string> {
  const abortController = new AbortController();
  const timer = window.setTimeout(() => abortController.abort(), timeoutMs);

  try {
    const credential = await navigator.credentials.get({
      otp: { transport: ['sms'] },
      signal: abortController.signal
    });

    if (isOTPCredential(credential)) {
      return credential.code;
    }

    throw new Error('未能获取到短信验证码');
  } catch (error) {
    if (error instanceof DOMException && error.name === 'AbortError') {
      throw new Error('验证码获取超时,请重新发送');
    }
    throw error;
  } finally {
    window.clearTimeout(timer);
  }
}

这段代码的核心在于 signal 属性的传递。navigator.credentials.get 在执行时接受一个 signal 选项,当外部调用 abort 时,请求会立即结束,并抛出 AbortError 异常。finally 块中清理定时器,避免内存泄漏。需要注意的是,浏览器只会在顶层页面且用户手势激活时显示短信接收提示,如果是从 iframe 中调用,很可能被拒绝。因此在实际项目中,建议在用户点击“获取验证码”按钮的事件回调里调用 getOTPCode,而不是在页面加载时主动调用。

另外,Web OTP 对短信文本格式有严格要求。短信最后一行必须包含 @ 符号,后面跟着域名,例如:您的验证码是 123456 @ipipp.com。浏览器会提取 @ 前的数字部分作为 code。发送方域名需要与当前页面域名一致或符合规范,否则浏览器不会解析。开发阶段可以使用本机模拟,但真实环境要注意这些限制。

有了上述类型定义和封装,TypeScript 项目里使用 Web OTP API 就不再需要担心类型缺失。建议将类型声明集中放在公共的 .d.ts 文件中,团队其他成员也能受益于准确的智能提示。随着 TypeScript 版本更新,lib.dom 可能会补全这些类型,届时可以删除自定义声明。当前阶段,手动补齐类型是保证类型安全最直接的办法。

TypeScriptWeb OTP API短信验证码自动填充修改时间:2026-10-04 09:08:11

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