我偶然发现Typescript中“隐藏”全局接口的问题:
以下代码拒绝进行类型检查:
interface Location {
location: string;
}
interface Named {
name: string;
}
interface NamedLoc extends Named, Location {
s: string;
}
let dd: NamedLoc = {
s: '3',
name: "asasf",
location: "asd"
};
,出现以下错误:
error TS2322: Type '{ s: string; name: string; location: string; }' is not assignable to type 'NamedLoc'.
Property 'hash' is missing in type '{ s: string; name: string; location: string; }'.
13 let dd: NamedLoc = {
~~
请注意,我定义了我自己的位置界面, 但是 SOMEHOW 打字稿采用的是位置接口的定义:
interface Location {
hash: string;
host: string;
hostname: string;
href: string;
readonly origin: string;
pathname: string;
port: string;
protocol: string;
search: string;
assign(url: string): void;
reload(forcedReload?: boolean): void;
replace(url: string): void;
toString(): string;
}
但是,这会检查!!?
interface Loc {
location: string;
}
interface Named {
name: string;
}
interface NamedLoc extends Named, Loc {
s: string;
}
let dd: NamedLoc = {
s: '3',
name: "asasf",
location: "asd"
};
我花了一些时间才弄清楚这里没有使用我定义的类型,但是还必须进行其他操作,因为即使我的编辑器也进入了局部语言定义的接口的定义中。
如果说将来会引入另一个与我当前应用程序中的一种名称相同的全局类型,那会发生什么?它将不再进行类型检查吗?
为什么会这样,这些幕布背后是怎么回事?
PS,我正在关注TS-docs:
答案 0 :(得分:1)
这里是您所看到的内容的说明。可以通过这个简短的示例进行复制。
interface Location {
location: string;
}
// Error!
const loc: Location = {
location: ''
}
您遇到的是multiple declarations within the same common root contribute to the same type。
因此,如果您的Location
接口是全局接口,它将添加到Location
一部分的现有lib.d.ts
接口中。
您可以使用模块或命名空间来避免这种情况:
namespace Example {
interface Location {
location: string;
}
// This works
const loc: Location = {
location: ''
}
}
如果文件导入或导出,它将是一个模块,不会出现问题,与命名空间示例中的相同。
答案 1 :(得分:1)
这里发生的是接口声明合并未显示,实际上是扩展内置类型的基本机制。如果在全局范围内定义接口,则无法避免这种情况。
您遇到的问题是经典的Javascript问题,即所有内容都在全局命名空间中。该问题的解决方案是使用模块,并且该解决方案同样适用于Typescript。如果您使用模块,则不会有将您的界面与全局界面合并的风险。
另一种解决方案是将所有代码再次置于专用的命名空间中,以避免合并行为。