这与AWS SDK有关,它有几个客户端,每个客户端都有带有属性的命名空间.

这个库导出AWS,它有几个客户端,例如DynamoDBACM.DynamoDB有一个名为DocumentClient的房产.ACM有一个名为CertificateBody的房产.

class _DocumentClient {}
namespace _DocumentClient {}

// DynamoDB that is imported in the AWS module (see below)
declare class _DynamoDB {}
declare namespace _DynamoDB {
  export import DocumentClient = _DocumentClient;
}

// ACM client that is imported in the AWS module (see below)
declare class _ACM {}
declare namespace _ACM {
  export type CertificateBody = string;
}

// AWS module (mimicking)
// The original library (as linked above) exports a lot more clients...
namespace AWS {
  export import ACM = _ACM;
  export import DynamoDB = _DynamoDB;
}

我试图创建一个类型,它产生一个像"DynamoDB.DocumentClient" | "ACM.CertificateBody"这样的字符串字面量的联合.

我已经try 获取每个客户端的所有属性的列表,但这似乎是一项不可能完成的任务,更不用说使用点符号附加客户端和属性了.

我只得到了prototype个字符串,而不是想要的DocumentClientCertificateBody个字符串.

// this works - ("ADM" | "DynamoDB")
type ClientName = keyof typeof AWS; 

// shouldn't this yield "DocumentClient" | "CertificateBody"? Using this type only means I can use "prototype" :/
type NestedClientName<C extends ClientName> = keyof typeof AWS[C]; 

// I want to be able to get a type with a union of string literals like `"ACM.CertificateBody" | "DynamoDB.DocumentClient" 
type NestedClientFullName<C extends ClientName, NC extends NestedClientName<C>> = `${C}.${NC}`; 

不幸的是,这NestedClientName个(因此,NestedClientFullName个)都没有产生公平的结果.

Here is a permalink to the full file on GitHub for context,以显示原始aws-sdk文件.我已经在上面的两个片段和下面的操场上复制了它.

Playground

推荐答案

根据代码示例,ACM实际上没有名为CertificateBody的属性,因此您所请求的是不可能的,至少对于涉及导出类型的任务部分是不可能的.


在TypeScrip中,namespaces既可以充当运行时存在并保存属性的values,也可以充当仅存在于TypeScrip代码中的namespaces for types.当您export命名空间中的值(如constfunction)时,它将成为命名空间值的属性.当您从命名空间导出类型(如interfacetype)时,它不会.

如果你有一个名为Foo的命名空间,那么typeof Foo将给你value的类型,名为Foo,它包含任何导出的值作为属性键. 它不会给你任何访问type namespace命名为Foo,或任何方式列出存在的类型. 实际上,没有办法在TypeScript中枚举类型:

declare namespace Foo {
    export const v: number;
    export type T = number;
}
type K = keyof typeof Foo;
// type K = "v"

只是为了强调类型和值是不同的:如果您导出only个类型,而不是名称空间中的值,则甚至不会有与名称空间对应的值:

declare namespace Bar {
    export const v: number;
}
const okay = Bar; // okay

declare namespace Baz {
    export type T = number;
}
const oops = Baz; // error

在上面的代码中,typeof Bar作为具有numberv属性的对象类型存在,但typeof Baz根本不是什么东西.没有名为Baz的值,你可以得到它的type.Bazonly个类型的命名空间.


因此,ACM没有名为CertificateBody的属性.取而代之的是,名字空间ACM具有称为CertificateBodytype.该类型可以在TypeScrip中直接引用为ACM.CertificateBody,但没有办法以编程方式访问它,并且绝对不能像"CertificateBody"那样作为字符串literal type.不幸的是,你想要做的事情是不可能的.

Playground link to code

Typescript相关问答推荐

类型脚本强制泛型类型安全

如何推断哪个特定密钥与泛型匹配?

react 路由6操作未订阅从react 挂钩表单提交+也不使用RTK查询Mutations

Angular 信号:当输入信号改变值时,S触发取数的正确方式是什么?

诡异的文字类型--S为物语的关键

TS如何不立即将表达式转换为完全不可变?

TypeScrip省略了类型参数,仅当传递另一个前面的类型参数时才采用默认类型

如何从扩展接口推断泛型?

函数重载中的不正确TS建议

具有自引用属性的接口

按函数名的类型安全类型脚本方法包装帮助器

对象类型的TypeScrip隐式索引签名

如何在脚本中输入具有不同数量的泛型类型变量的函数?

类型推断对React.ForwardRef()的引用参数无效

两个名称不同的相同打字界面-如何使其干燥/避免重复?

基于区分的联合键的回调参数缩小

如何键入';v型';

有没有一种简单的方法可以访问Keyboard Shortcuts JSON文件中列出的每个命令的显示名称(标题)?

我应该使用服务方法(依赖于可观察的)在组件中进行计算吗?

从 npm 切换到 pnpm 后出现Typescript 错误