如何创建生成嵌套类属性点记法字符串字面量的TypeScript类型?
问题与解决方案
问题背景
AWS SDK导出的AWS对象包含多个客户端(如DynamoDB、ACM),每个客户端同时以类和命名空间的形式存在:
DynamoDB命名空间下包含DocumentClient属性ACM命名空间下包含CertificateBody类型
模拟的TypeScript类型定义如下:
class _DocumentClient {} namespace _DocumentClient {} // DynamoDB 客户端(将被导入到AWS模块) declare class _DynamoDB {} declare namespace _DynamoDB { export import DocumentClient = _DocumentClient; } // ACM 客户端(将被导入到AWS模块) declare class _ACM {} declare namespace _ACM { export type CertificateBody = string; } // 模拟AWS模块(实际包含更多客户端) namespace AWS { export import ACM = _ACM; export import DynamoDB = _DynamoDB; }
目标是生成一个字符串字面量联合类型,如"DynamoDB.DocumentClient" | "ACM.CertificateBody",但尝试的代码仅能获取到"prototype",无法得到预期的属性名:
// 正常获取客户端名称联合类型:"ACM" | "DynamoDB" type ClientName = keyof typeof AWS; // 预期得到 "DocumentClient" | "CertificateBody",但实际仅能拿到 "prototype" type NestedClientName<C extends ClientName> = keyof typeof AWS[C]; // 期望生成点记名字符串联合类型,但结果不符合预期 type NestedClientFullName<C extends ClientName, NC extends NestedClientName<C>> = `${C}.${NC}`;
解决方案
问题根源在于typeof AWS[C]指向的是类的构造函数类型,keyof只能获取到构造函数的默认属性(如prototype),而非命名空间下的成员。我们需要直接访问客户端的命名空间类型,才能获取到目标成员。
方法1:手动映射命名空间类型
直接创建客户端命名空间的类型映射,明确关联每个客户端与其命名空间:
// 定义客户端与对应命名空间的类型映射 type AWSClientNamespaces = { ACM: typeof _ACM; DynamoDB: typeof _DynamoDB; }; // 获取所有客户端名称 type ClientName = keyof AWSClientNamespaces; // 获取指定客户端命名空间下的成员键 type NestedClientName<C extends ClientName> = keyof AWSClientNamespaces[C]; // 生成完整的点记名字符串联合类型 type NestedClientFullName = { [C in ClientName]: `${C}.${NestedClientName<C>}`; }[ClientName]; // 验证结果:NestedClientFullName = "ACM.CertificateBody" | "DynamoDB.DocumentClient" type TestResult = NestedClientFullName;
方法2:利用类型推断自动关联(适配实际AWS SDK)
在实际AWS SDK的类型定义中,客户端的类与命名空间是合并的,命名空间成员会作为类的静态属性存在。此时可以通过typeof AWS[C]的静态属性来获取,但需要过滤掉默认的构造函数属性:
// 获取所有客户端名称 type ClientName = keyof typeof AWS; // 过滤掉构造函数默认属性,仅保留命名空间成员 type NestedClientName<C extends ClientName> = Exclude<keyof typeof AWS[C], "prototype">; // 生成完整的点记名字符串联合类型 type NestedClientFullName = { [C in ClientName]: `${C}.${NestedClientName<C>}`; }[ClientName];
说明
- 第一种方法更直观,适合模拟场景或需要精确控制的情况;
- 第二种方法适配实际AWS SDK的类型结构,无需手动维护映射关系;
- 两种方法最终都能生成目标字符串字面量联合类型,满足需求。
内容的提问来源于stack exchange,提问作者LuchoTurtle
相关产品推荐
相关产品推荐

