下一个例子是试图重载命名空间N
但不幸的是编译器抱怨A
和B
都不是它的导出成员。
namespace N
{
export const A = 'hello';
export const B = 'world';
}
type N = N.A | N.B;
const a: N = N.A;
const b: N = N.B;
console.log(a, b);
尽管如此,运行已编译的代码会产生以下预期输出:
hello world
所以问题显然是:为什么编译器会抱怨?抱怨是否合理?
注1:我使用的编译器版本是
3.1.1
注意2:我知道上面的内容可以写成
enum
但请记住,这是我想要实现的一个过于简单的例子,因此这只是证明问题的最低限度。
问题是常量是值,而不是类型。要获得常量的类型,您需要使用typeof
namespace N
{
export const A = 'hello';
export const B = 'world';
}
type N = typeof N.A | typeof N.B;
const a: N = N.A;
const b: N = N.B;
console.log(a, b);
注意:类型和命名空间并不真正共享任何共同点,它们是碰巧共享相同名称的不同符号。没有合并行为(例如,可能有接口和类)
编辑
问:为什么N.A
的类型不是string
?
答:N.A的类型不是字符串,因为您使用了const
声明。如果使用const,则推断出最窄的类型。在这种情况下,这是字符串文字类型“hello”。
问:为什么type N = "hello" | "world"
工作但不是type N = N.A | N.B;
?
答:Typescript允许使用字符串文字作为我们在上面看到的类型。但他们是类型。你不能在表达式中使用它们,你只能在类型注释中使用N
(即这样做也不起作用let a = N
)。另一方面,变量是一个值。您可以在表达式中使用它,而不是在类型注释中使用它(例如let o:N.A
是一个错误)。要获得变量的类型,您需要typeof
(所以这将起作用:let o: typeof N.A
)