TypeScript如何实现嵌套原始类型标注,规范不一致API返回的字段类型
可行方案汇总
以下三个方案可以覆盖不同场景的需求:
方案1:Branded 类型标注(无运行时开销)
这是最贴近你期望写法的轻量方案,仅在 TypeScript 类型层面增加标注,不会改变值的实际运行时属性:
// 通用承载类型定义 type StringOf<T> = string & { /** 字符串内部承载的实际值类型 */ __converted_type?: T } // 响应接口定义 interface ApiResponse { // 标注为内容是数字的字符串 foo: StringOf<number> // 标注为内容是布尔值的字符串 service: StringOf<boolean> }
使用时直接把接口返回的原始对象断言为ApiResponse类型即可,不需要额外代码,适合只需要类型提示、不需要自动转换值的场景。
方案2:搭配类型守卫实现运行时校验
如果需要在运行时确保字段内容符合预期,可以补充类型守卫函数,同时实现类型收窄:
// 数字内容字符串的类型守卫 function isNumberString(val: string): val is StringOf<number> { return !isNaN(Number(val)) } // 使用示例 const rawRes = await fetch('/xxx').then(res => res.json()) as ApiResponse if (isNumberString(rawRes.foo)) { // 此处 TS 可以识别 rawRes.foo 为数字内容字符串,转换后类型安全 const realNum = Number(rawRes.foo) }
方案3:全链路类型安全转换(推荐生产环境使用)
如果希望直接拿到转换后为真实类型的响应对象,可以通过定义转换 schema 实现一次配置、全局可用,同时保证类型完全匹配:
// 1. 定义你最终需要的真实响应类型(非字符串格式) interface ActualResponse { foo: number service: boolean } // 2. 定义转换规则,TS 会自动校验规则和类型是否匹配 type ConversionSchema<T> = { [K in keyof T]: (rawValue: string) => T[K] } const responseSchema: ConversionSchema<ActualResponse> = { foo: val => Number(val), service: val => val === 'true' } // 3. 通用转换函数 function convertResponse<T>(raw: Record<keyof T, string>, schema: ConversionSchema<T>): T { return Object.fromEntries( Object.entries(raw).map(([k, v]) => [k, schema[k as keyof T](v)]) ) as T } // 使用示例 const raw = await fetch('/xxx').then(res => res.json()) const res = convertResponse<ActualResponse>(raw, responseSchema) // 此时 res.foo 直接是 number 类型,res.service 直接是 boolean 类型,无需额外转换
三个方案可以按需选择:仅需要标注选方案1,需要局部校验选方案2,生产环境推荐用方案3实现完全的类型安全。
内容的提问来源于stack exchange,提问作者Ctfrancia
相关产品推荐
相关产品推荐

