ts - 类型收窄

文章目录

    • 问题描述
    • 为什么会出现这个错误?
      • [1. 类型推断机制](#1. 类型推断机制)
      • [2. 函数参数要求具体字面量类型](#2. 函数参数要求具体字面量类型)
      • [3. 类型不匹配](#3. 类型不匹配)
    • 解决方案
      • [方案 1:使用类型断言](#方案 1:使用类型断言)
      • [方案 2:声明 routers 为常量](#方案 2:声明 routers 为常量)
      • [方案 3:显式类型注解](#方案 3:显式类型注解)
      • [方案 4:使用类型提取](#方案 4:使用类型提取)
    • 最佳实践

问题描述

TypeScript 中,我们经常会遇到类似以下的代码和错误。

为什么下面的代码 goRoute(routers.admin) 会报错?

typescript 复制代码
const routers = {
  home: "/",
  admin: "/admin",
  user: "/user"
};

const goRoute = (r: "/" | "/admin" | "/user") => {};

goRoute(routers.admin); // 报错行: 类型"string"的参数不能赋给类型'"/" | "/admin" | "/user"'的参数。

报错如下图:

为什么会出现这个错误?

1. 类型推断机制

TypeScript 会对 routers 具体的字符串字面量类 会将对象字面量的属性类型推断为最宽泛的类型 ,即 string 类型。

所以 routers 的实际类型被推断为:

typescript 复制代码
{
  home: string;
  admin: string;
  user: string;
}

2. 函数参数要求具体字面量类型

goRoute 函数要求参数必须是三个具体的字符串字面量类型之一:'/' | '/admin' | '/user'

3. 类型不匹配

当我们尝试传递 routers.admin(类型为 string)给 goRoute(需要 '/' | '/admin' | '/user')时,TypeScript 会报错,因为 string 比具体的字符串字面量类型更宽泛。

解决方案

方案 1:使用类型断言

typescript 复制代码
goRoute(routers.admin as "/admin");

这种方法简单直接,但不够安全,因为如果 routers.admin 的值后来被修改,类型断言可能会掩盖真正的错误。

方案 2:声明 routers 为常量

typescript 复制代码
const routers = {
  home: "/",
  admin: "/admin",
  user: "/user"
} as const;

as const 是 TypeScript 的常量断言,它会告诉 TypeScript 将所有属性值视为字面量类型,而不是 string 类型。

此时 routers 的类型变为:

typescript 复制代码
{
  readonly home: '/';
  readonly admin: '/admin';
  readonly user: '/user';
}

方案 3:显式类型注解

typescript 复制代码
interface Routes {
  home: "/";
  admin: "/admin";
  user: "/user";
}

const routers: Routes = {
  home: "/",
  admin: "/admin",
  user: "/user"
};

这种方法更显式地定义了类型,适合更复杂的场景。

方案 4:使用类型提取

typescript 复制代码
const routers = {
  home: "/",
  admin: "/admin",
  user: "/user"
};

type RouterValues = (typeof routers)[keyof typeof routers];

const goRoute = (r: RouterValues) => {};

这种方法动态地从 routers 对象中提取所有值的类型作为联合类型。

最佳实践

对于路由配置这种通常不会改变的结构,推荐使用 as const 方案:

typescript 复制代码
const routers = {
  home: "/",
  admin: "/admin",
  user: "/user"
} as const;
const goRoute = (r: "/" | "/admin" | "/user") => {};
goRoute(routers.admin);

这种方式的优点:

  1. 保持代码简洁
  2. 类型安全
  3. 易于维护(添加新路由时类型会自动更新)
  4. 避免硬编码类型

👉点击进入 我的网站

相关推荐
QQ1__81151751520 小时前
Spring boot名城小区物业管理系统信息管理系统源码-SpringBoot后端+Vue前端+MySQL【可直接运行】
前端·vue.js·spring boot
钛态20 小时前
前端微前端架构:大项目的救命稻草还是自找麻烦?
前端·vue·react·web
一粒黑子20 小时前
【实战解析】阿里开源 PageAgent:纯前端 GUI Agent,一行JS让网页支持自然语言操控
前端·javascript·开源
独角鲸网络安全实验室20 小时前
2026微信小程序抓包全解析:从实操落地到合规风控,解锁前端调试新范式
前端·微信小程序·小程序·抓包·系统代理绕过·https证书严格校验·进程隔离
紫微AI20 小时前
前端文本测量成了卡死一切创新的最后瓶颈,pretext实现突破了
前端·人工智能·typescript
GISer_Jing20 小时前
AI前端(From豆包)
前端·aigc·ai编程
IT枫斗者20 小时前
前端部署后如何判断“页面是不是最新”?一套可落地的版本检测方案(适配 Vite/Vue/React/任意 SPA)
前端·javascript·vue.js·react.js·架构·bug
测试修炼手册20 小时前
[测试技术] 深入理解 JSON Web Token (JWT)
前端·json
AI老李20 小时前
2026 年 Web 前端开发的 8 个趋势!
前端
里欧跑得慢20 小时前
15. Web可访问性最佳实践:让每个用户都能平等访问
前端·css·flutter·web