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

TypeScript三级属性类型索引报错:Type cannot be used to index type

问题:常量三级属性类型定义报错处理

在为常量的三级属性定义类型时,出现了意外的索引错误。尽管类型实际使用时行为符合预期,但定义SelectedActorSelectedOptionSections时,TypeScript提示Type '"sections"' cannot be used to index type 'SelectedActorSelectedOption<T, O>',需要消除该报错。

复现代码

interface ActorOptionSection<K extends string = string> {
  key: K;
}

interface ActorOption<K extends string = string> {
  key: K;
  sections: Record<string, ActorOptionSection<string>>;
}

interface Actor<K extends string = string> {
  key: K;
  options: Record<string, ActorOption<string>>;
}

const ActorMap = {
  alice: {
    key: "alice",
    options: {
      optA1: {
        key: "optA1",
        sections: {
          sectionA11: {
            key: "sectionA11"
          }
        }
      },
      optA2: {
        key: "optA2",
        sections: {
          sectionA21: {
            key: "sectionA21"
          }
        }
      }
    }
  },
  bob: {
    key: "bob",
    options: {
      optB1: {
        key: "optB1",
        sections: {
          sectionB11: {
            key: "sectionB11",
          }
        }
      },
      optB2: {
        key: "optB2",
        sections: {
          sectionB21: {
            key: "sectionB21",
          }
        }
      }
    }
  }
} as const satisfies Record<string, Actor<string>>;

type TypeOfMap = typeof ActorMap;
type ActorKey = keyof typeof ActorMap;
type SelectedActor<T extends ActorKey> = TypeOfMap[T];
type SelectedActorOptions<T extends ActorKey> = SelectedActor<T>["options"];
type KeyOfSelectedActorOptions<T extends ActorKey> = keyof SelectedActorOptions<T>;
type SelectedActorSelectedOption<T extends ActorKey, O extends KeyOfSelectedActorOptions<T>> = SelectedActorOptions<T>[O];
type SelectedActorSelectedOptionSections<T extends ActorKey, O extends KeyOfSelectedActorOptions<T>> = SelectedActorSelectedOption<T, O>["sections"]
// Unexpected error: Type '"sections"' cannot be used to index type 'SelectedActorSelectedOption<T, O>'.(2536)


// No error (as expected)
const aliceOptA1Sections: SelectedActorSelectedOptionSections<"alice", "optA1"> = { sectionA11: { key: "sectionA11" } };

// Error (as expected): Object literal may only specify known properties, but 'sectionA11' does not exist in type '{ readonly sectionA21: { readonly key: "sectionA21"; }; }'. Did you mean to write 'sectionA21'?(2561)
const aliceOptA2Sections: SelectedActorSelectedOptionSections<"alice", "optA2"> = { sectionA11: { key: "sectionA11" } };

问题原因

TypeScript无法在泛型层面确认SelectedActorSelectedOption<T, O>一定包含sections属性。虽然Actor系列接口明确了ActorOption拥有sections,但as const生成的具体只读类型与接口的关联,在泛型推导中没有被显式传递,导致编译器无法确定该属性的存在。

解决方案

方案1:为SelectedActorSelectedOption添加显式接口约束

修改SelectedActorSelectedOption的定义,通过交叉类型明确它符合ActorOption<string>结构,让编译器确认sections属性存在:

type SelectedActorSelectedOption<T extends ActorKey, O extends KeyOfSelectedActorOptions<T>> = SelectedActorOptions<T>[O] & ActorOption<string>;

修改后,SelectedActorSelectedOptionSections的索引操作就不会再报错,同时保留原有的具体字面量类型检查。

方案2:直接基于接口结构推导类型

如果不需要严格保留ActorMap的具体字面量类型,可直接从Actor接口出发定义类型:

type SelectedActorSelectedOptionSections<T extends ActorKey, O extends keyof Actor<string>['options']> = Actor<string>['options'][O]['sections'];

但此方法会丢失ActorMap中具体的键(如optA1、sectionA11)的类型提示,仅保留接口定义的结构,适合不需要依赖具体常量值的场景。

效果验证

修改后,SelectedActorSelectedOptionSections的定义不再报错,同时使用时依然能正确校验属性:

  • 正确赋值无报错
  • 传入不存在的section键时,依然会触发预期的类型错误

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.25 02:45:25