TypeScript嵌套路由联合类型问题:多余属性未触发编译错误
解决TypeScript嵌套路由联合类型允许多余属性的问题
问题出在TypeScript的结构类型系统特性上:当你用对象字面量赋值给联合类型时,只要字面量满足联合类型中某一个类型的必填属性,TypeScript就会认为它匹配该类型,多余的属性不会触发编译错误。比如你例子里的对象有prefix和routes,满足IPrefixApiRoute的必填字段,所以TypeScript忽略了额外的method属性,没有报错。
要解决这个问题,我们需要让每个路由类型显式禁止不属于它的属性,具体可以通过添加?: never类型的属性来实现——这会告诉TypeScript,这些属性不能被赋值(否则会触发类型冲突)。
方案1:手动添加禁止属性
直接在两个接口中添加对方属性的never类型声明:
type Method = "GET" | "DELETE" | "HEAD" | "OPTIONS" | "POST" | "PUT" | "PATCH"; interface IApiRoute { route: string; method: Method; routeParams: string[]; queryParams: string[]; name: string; // 禁止前缀路由的属性存在 prefix?: never; routes?: never; } interface IPrefixApiRoute { prefix: string; routes: Array<IRawApiRoute>; // 禁止普通路由的属性存在 route?: never; method?: never; routeParams?: never; queryParams?: never; name?: never; } type IRawApiRoute = IApiRoute | IPrefixApiRoute;
此时再运行你的错误代码:
const array: Array<IRawApiRoute> = [ { prefix: "auth", routes: [], method: "GET", // 编译错误:类型"{ prefix: string; routes: never[]; method: "GET"; }"不能赋给类型"IRawApiRoute" }, ];
TypeScript会正确触发编译错误,符合你的需求。
方案2:用工具类型自动生成(更灵活)
如果接口属性较多或后续可能修改,可以用TypeScript的工具类型自动生成严格的类型,避免手动维护never属性:
type Method = "GET" | "DELETE" | "HEAD" | "OPTIONS" | "POST" | "PUT" | "PATCH"; // 定义基础接口,不包含禁止规则 interface IApiRouteBase { route: string; method: Method; routeParams: string[]; queryParams: string[]; name: string; } interface IPrefixApiRouteBase { prefix: string; routes: Array<IRawApiRoute>; } // 生成严格的普通路由:排除前缀路由的所有属性 type IApiRoute = IApiRouteBase & { [K in keyof IPrefixApiRouteBase]?: never }; // 生成严格的前缀路由:排除普通路由的所有属性 type IPrefixApiRoute = IPrefixApiRouteBase & { [K in keyof IApiRouteBase]?: never }; type IRawApiRoute = IApiRoute | IPrefixApiRoute;
这个方案的原理是通过交叉类型,将基础接口与一个“禁止对方所有属性”的类型合并,实现和方案1相同的效果,但更易于维护。
内容的提问来源于stack exchange,提问作者Muhammad Waqar
相关产品推荐
相关产品推荐

