使用泛型作为类型索引时TypeScript类型错误排查
强类型项目-应用-配置结构的类型错误排查
我想要创建一个类型结构,用于定义一组项目(如软件项目),每个项目包含一个或多个应用(如API、UI),每个应用可拥有强类型配置属性(secrets、环境变量)。但编写代码时出现以下类型错误:
Type 'TProjectKey' cannot be used to index type 'AllProjects'.
Type "apps" cannot be used to index type 'AllProjects[TProjectKey]'.
Type 'TAppType' cannot be used to index type 'AllProjects[TProjectKey]["apps"]'.
Type "secrets" cannot be used to index type 'AllProjects[TProjectKey]["apps"][TAppType]'.
我的目标是让配置对象实现强类型化:必填secret必须提供,可选secret可省略,同时希望无必填secret时相关配置项非必填。以下是我的尝试代码:
enum ProjectKey { Project1 = "projectOne", Project2 = "projectTwo", } enum AppType { API = "api", UI = "ui", } type Project<TProjectKey extends ProjectKey> = { key: TProjectKey; name: string; apps: Partial<{ [ TAppType in AppType ]: App<TAppType> }>; } type App<TAppKey extends AppType = AppType, TSecretKeys extends string = never> = { type: TAppKey; name: string; secrets: Secrets<TSecretKeys>; } type OptionalSecret = { defaultValue?: string; }; type RequiredSecret = { required: true; }; type Secret = OptionalSecret | RequiredSecret; type Secrets<TSecretKeys extends string> = { [ K in TSecretKeys ]: Secret }; // Define a project. const Project1: Project<ProjectKey.Project1> = { key: ProjectKey.Project1, name: "Project One", apps: { api: { type: AppType.API, name: "Project One API", secrets: { "SECRET_1": { required: true }, "SECRET_2": { defaultValue: "abc" }, }, }, }, }; // Roll up all projects into a mapped type. type AllProjects = { [ ProjectKey.Project1 ]: typeof Project1; }; // Define a configuration which describes all of the projects. type Config = { [ TProjectKey in ProjectKey ]?: ProjectConfigProps<TProjectKey>; }; type ProjectConfigProps<TProjectKey extends ProjectKey> = { apps: { [ TAppType in AppType ]: AppConfigProps<TProjectKey, TAppType> }; }; // Error occurs below. type AppConfigProps<TProjectKey extends ProjectKey, TAppType extends AppType> = { secrets?: { [ TSecretKey in keyof AllProjects[ TProjectKey ][ "apps" ][ TAppType ][ "secrets" ] ]: AllProjects[ TProjectKey ][ "apps" ][ TAppType ][ "secrets" ][ TSecretKey ] typeof RequiredSecret ? { value: string } : { value?: string } }; }; // Usage -- the goal is to strongly type the configuration object so that each required secret must be provided, and each optional one may or may not. const config: Config = { "projectOne": { apps: { api: { secrets: { SECRET_1: { value: "some_required_value" }, SECRET_2: { value: "some_default_value" }, // Or SECRET_2 can just not be supplied. } }, // How to make this not required if there are no required secrets? ui: { secrets: undefined, }, }, }, };
内容的提问来源于stack exchange,提问作者Josh M.
相关产品推荐
相关产品推荐

