You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

TypeScript多次泛型索引后无法用字符串字面量索引类型的原因

问题:TypeScript泛型中使用字符串字面量索引嵌套类型报错的原因

问题背景

我用openapi-typescript生成了大型嵌套类型,想写一个受该类型约束的函数,接收path->method->status参数。以下是简化的示例说明问题:

报错的代码示例

type ApiSpec = {
    todos: {
        "GET": {
            responses:  {
                200: {
                        foo: string; 
                        bar: string; 
                    }; 
                400: {
                    biz: string;
                    bash: string;
                };
            }
  
        }, 
    }
}

function fieldAt<
    TPath extends keyof ApiSpec,
    TMethod extends keyof ApiSpec[TPath],
    // 报错:Type '"responses"' cannot be used to index type 'ApiSpec[TPath][TMethod]'.(2536)
    TStatus extends keyof ApiSpec[TPath][TMethod]["responses"], 

> (
    key: TPath, 
    method: TMethod, 
    status: TStatus, 
    fieldName: keyof ApiSpec[TPath][TMethod]["responses"][TStatus]
){

}

可行的代码示例

把"responses"作为泛型参数传入后,代码能正常运行:

type ApiSpec = {
    todos: {
        "GET": {
            responses:  {
                200: {
                        foo: string; 
                        bar: string; 
                    }; 
                400: {
                    biz: string;
                    bash: string;
                };
            }, 
            somethingElse: {
                foo: "bar"
            }

        }, 
    }
}

function fieldAt<
    TPath extends keyof ApiSpec,
    TMethod extends keyof ApiSpec[TPath],
    // 此处正常
    TSomething extends keyof ApiSpec[TPath][TMethod] & "responses",

    // 此处正常
    TStatus extends keyof ApiSpec[TPath][TMethod][TSomething], 

> (
    key: TPath, 
    method: TMethod, 
    status: TStatus, 
    fieldName: keyof ApiSpec[TPath][TMethod][TSomething][TStatus]
){

}

fieldAt("todos", "GET", 200, "foo")

报错原因分析

TypeScript在泛型约束的检查阶段,不会默认假设ApiSpec[TPath][TMethod]一定包含"responses"这个键。虽然你当前定义的ApiSpec里todos的GET方法有responses,但泛型约束只保证TMethod是ApiSpec[TPath]的合法键,却无法提前确认该方法对应的类型里必然存在"responses"属性——如果后续ApiSpec新增一个没有responses的路径或方法,第一种写法的泛型定义就会直接失效。

而第二种写法中,把"responses"作为泛型参数TSomething,并通过& "responses"约束它只能是"responses",相当于明确告诉TypeScript:我们只处理那些包含"responses"键的方法类型。此时ApiSpec[TPath][TMethod][TSomething]的访问是绝对安全的,因为TSomething已经被约束为当前方法类型中存在的键且等于"responses"。

简单总结:第一种写法里TypeScript无法确保所有ApiSpec[TPath][TMethod]都有responses,第二种写法通过泛型参数的双重约束,明确了处理范围,所以不会触发索引错误。

内容的提问来源于stack exchange,提问作者dwjohnston

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 01:27:13