TypeScript中如何限定函数仅接收接口定义的属性值作为参数
实现方案
问题根源是你给APIs显式标注APIRoutes类型时,TS会自动把属性值类型拓宽为普通string,丢失了具体的字面量信息,自然没法做值的合法性校验。按下面的方式改即可:
第一步:修正APIs常量的类型定义
去掉显式的APIRoutes类型注解,用as const把整个对象收窄为只读字面量类型,让TS能精确推断每个属性的具体值:
const APIs = { SIGNUP: Config.baseURL + "/signup", LOGIN: Config.baseURL + "/login", } as const;
如果需要保留原来的APIRoutes接口做结构约束,推荐用TS 4.9+支持的satisfies关键字做校验,不会丢失字面量类型推断:
interface APIRoutes { SIGNUP: string, LOGIN: string } const APIs = { SIGNUP: Config.baseURL + "/signup", LOGIN: Config.baseURL + "/login", } as const satisfies APIRoutes;
第二步:提取合法路由值的联合类型
直接从APIs的类型里提取所有属性值的联合,作为函数参数的合法类型:
type ValidAPIRoute = typeof APIs[keyof typeof APIs];
第三步:修改函数的参数类型
把第一个参数的类型从string换成上面定义的ValidAPIRoute即可:
const callAPI = async (APIRoute: ValidAPIRoute, body: any, headers: any) => { // 你的业务逻辑 }
校验效果
callAPI(APIs.SIGNUP, {}, {}):类型校验通过callAPI(APIs.STACKOVERFLOWISAWESOME, {}, {}):直接报类型错误,因为APIs本身不存在这个属性callAPI("/random/route", {}, {}):报类型错误,传入的字符串不在合法路由值范围内
特殊场景处理
如果你的Config.baseURL是动态读取的(比如从环境变量获取,类型本身就是宽泛的string),拼接后的路由值在类型层面也会是普通string,没法直接通过字面量区分,这时候可以用**烙印类型(Branded Type)**给合法路由打标记:
type ValidAPIRoute = string & { __brand: "APIRoute" }; const APIs = { SIGNUP: (Config.baseURL + "/signup") as ValidAPIRoute, LOGIN: (Config.baseURL + "/login") as ValidAPIRoute, }; const callAPI = async (APIRoute: ValidAPIRoute, body: any, headers: any) => { // 业务逻辑 }
这种方案同样能拦住非法字符串传入,只有你显式标记为ValidAPIRoute的路由值才能正常传参。
内容的提问来源于stack exchange,提问作者Freshman
相关产品推荐
相关产品推荐

