TypeScript访问映射Proxy对象时键类型丢失特异性的解决问询
问题:如何阻止索引签名中的
key被拓宽为string? 基础示例问题
能否阻止key被拓宽为string?
type Foo = { [key in string]: key } type Test = Foo['bar'] // ^? type Test = string
如何让Test的类型为'bar'而非string?
实际场景背景
我正在为API访问用的Proxy定义类型。该API部分端点预先已知,部分未知,因此Proxy需要同时支持已知字符串(如'a' | 'b' | 'c')和任意未知字符串(string)。
先定义已知端点的schema:
type Paths = { '/a/b/{id}': {} 'foo/bar': {} }
还有一个推断URL动态部分的类型工具:
type ExtractParams<url extends string> = url extends `${string}{${infer A extends string}}${string}` ? {[param in A]: string} : {} type test = ExtractParams<'/a/b/{foo}'> // ^? type test = { foo: string }
我最初为Proxy编写的类型如下:
type MyProxy = { [key in keyof Paths]: ExtractParams<key> } & { [key in string]: ExtractParams<key> }
这个类型允许访问任意字符串:
MyProxy['/a/b/{id}'] // 已知端点,正常 MyProxy['/la/la/la'] // 未知端点,正常
但问题在于,TypeScript无法正确推断未知端点的动态部分——因为[key in string]中的key会被简化为string,而非保留具体字符串值:
type knownPathParam = MyProxy['/a/b/{id}'] // ^? type knownPathParam = { id: string } <-- 正确 type unknownPathParam = MyProxy['/d/e/{id}'] // ^? type unknownPathParam = {} <-- 错误,期望为{ id: string }
正如基础示例所示,ExtractParams单独使用时正常,但放到[key in string]索引签名中后,key会被拓宽为string:
type BasicDemo = { [key in string]: key } type test = BasicDemo['some specific string'] // ^? type test = string
有没有办法让key保留被访问时的特定字符串类型?
解决方案
常规索引签名会统一将key视为string,无法保留具体字面量信息。要解决这个问题,需要用泛型+条件类型替代索引签名,让TypeScript保留传入的具体字符串类型:
方案1:泛型索引类型
直接将MyProxy定义为泛型,通过条件分支适配已知/未知路径:
type MyProxy<K extends string = string> = K extends keyof Paths ? ExtractParams<K> : ExtractParams<K> // 使用示例 type knownPathParam = MyProxy<'/a/b/{id}'> // { id: string } type unknownPathParam = MyProxy<'/d/e/{id}'> // { id: string } type anyPath = MyProxy // 对应任意string的类型,即{}
方案2:模拟Proxy的get签名(更贴合实际场景)
如果要模拟Proxy的类型结构,可通过接口的get方法签名实现:
interface MyProxy { get<K extends string>(key: K): K extends keyof Paths ? ExtractParams<K> : ExtractParams<K> }
核心原理
泛型会保留传入的具体字符串字面量类型,让ExtractParams能直接接收该字面量进行解析,而非接收被拓宽后的string类型,从而正确推断出URL中的动态参数。
内容的提问来源于stack exchange,提问作者Sheraff
相关产品推荐
相关产品推荐

