Typescript 生成带有“#private;”字段的声明 d.ts 文件
Typescript generates declaration d.ts file with `#private;` field
我有一个用 Typescript 编写的库,它分布在 2 个文件中:一个编译的 ECMAScript-2015 兼容 Javascript 文件 index.js
和一个 Typescript 声明文件 index.d.ts
。我的目标是让 Javascript 和 Typescript 开发人员都可以访问库(这样他们就有正确的输入和自动完成功能)。
最近我升级到 Typescript 3.9.7,并决定重构我的代码以使用新的私有 class 字段声明,该声明利用 #
sigil 而不是 Typescript 的 private
关键字。
令我惊讶的是,由于在我的 classes 中包含 #private;
成员,我的 index.d.ts
文件变得与旧的 Typescript 版本不兼容。
这是生成旧声明文件的旧 Typescript 代码与生成新的不兼容声明文件的新重构 Typescript 代码之间的比较。使用 private
关键字的旧代码:
// index.ts
class MyClass {
private field1: string = "foo";
private field2: string = "bar";
constructor() {
console.log(this.field1, this.field2);
}
}
// generated index.d.ts
declare class MyClass {
private field1;
private field2;
constructor();
}
使用#
sigil 声明私有名称的新重构代码:
// index.ts
class MyClass {
#field1: string = "foo";
#field2: string = "bar";
constructor() {
console.log(this.#field1, this.#field2);
}
}
// generated index.d.ts
declare class MyClass {
#private;
constructor();
}
这是包含该示例代码的 a page at Typescript playground。
现在,如果我的客户使用旧的 Typescript(比方说,版本 3.7)将获取我的库(由编译的 index.js
和声明文件 index.d.ts
组成,没有源代码 index.ts
文件)并依赖 index.d.ts
类型,他们会看到以下错误:
error TS1127: Invalid character.
该错误的来源很清楚(#
印记),所以我的问题如下:
- 如果我在将库发送给客户之前对
index.d.ts
进行后处理并删除 #private;
行,这样可以吗,他们不必了解实施细节?我可以通过使用 ttsc
包轻松地做到这一点,但我仍然担心那条打字信息可能在某种程度上很重要。
index.d.ts
中 #private;
行的实际用途是什么?为什么声明文件会暴露 class 使用私有字段,如果它们无论如何都无法访问,并且是实现细节?
- 根据 a topic in Typescript Github issues,这是预期的行为,因此带有私有字段的 classes 在发送到
.d.ts
文件时保留其标称的键入行为。可悲的是,这种解释的意义从我身上溜走了。是否有任何我可以阅读的额外文档以更好地理解 Typescript 的名义打字行为?
#private 语法目前是 stage-3 proposal for javascript。一旦浏览器支持它,它就不会被打字稿转译。
它使类型成为“标称”类型,因此公开相同 public 成员的其他类型不被视为与具有私有字段的类型兼容。这很重要的一种情况是,如果您有这样的代码:
class C {
#foo = "hello";
bar = 123;
static log(instance: C) {
console.log("foo = ", instance.#foo, " bar = ", instance.bar);
}
}
我敢肯定还有更多示例,但这个静态方法只是我想到的一个。
此 C.log
函数需要 C
class 的实际实例,因为它访问 instance
参数上的私有命名实例字段。如果声明 emit 没有通过指示它具有 ES 私有字段来反映 C
类型是名义上的,而是仅发出 public 字段,则编译器将在此处使用结构类型比较并且不会' t 产生预期的类型错误。例如,该声明 emit 将允许依赖代码将 { bar: 456 }
传递给 C.log
而不会出现任何编译器错误。
我试图回答你的问题但无法回答,然后我出于好奇问了我自己的问题,这是由一位 TypeScript 贡献者回答的,你可以在这里找到他的答案:What's the purpose of #private in TypeScript definition files?
总而言之,在某些情况下,私有字段在比较类型时很重要,这就是 #private
字段出现的原因,因此“包含私有成员”的信息是类型的一部分定义。
我有一个用 Typescript 编写的库,它分布在 2 个文件中:一个编译的 ECMAScript-2015 兼容 Javascript 文件 index.js
和一个 Typescript 声明文件 index.d.ts
。我的目标是让 Javascript 和 Typescript 开发人员都可以访问库(这样他们就有正确的输入和自动完成功能)。
最近我升级到 Typescript 3.9.7,并决定重构我的代码以使用新的私有 class 字段声明,该声明利用 #
sigil 而不是 Typescript 的 private
关键字。
令我惊讶的是,由于在我的 classes 中包含 #private;
成员,我的 index.d.ts
文件变得与旧的 Typescript 版本不兼容。
这是生成旧声明文件的旧 Typescript 代码与生成新的不兼容声明文件的新重构 Typescript 代码之间的比较。使用 private
关键字的旧代码:
// index.ts
class MyClass {
private field1: string = "foo";
private field2: string = "bar";
constructor() {
console.log(this.field1, this.field2);
}
}
// generated index.d.ts
declare class MyClass {
private field1;
private field2;
constructor();
}
使用#
sigil 声明私有名称的新重构代码:
// index.ts
class MyClass {
#field1: string = "foo";
#field2: string = "bar";
constructor() {
console.log(this.#field1, this.#field2);
}
}
// generated index.d.ts
declare class MyClass {
#private;
constructor();
}
这是包含该示例代码的 a page at Typescript playground。
现在,如果我的客户使用旧的 Typescript(比方说,版本 3.7)将获取我的库(由编译的 index.js
和声明文件 index.d.ts
组成,没有源代码 index.ts
文件)并依赖 index.d.ts
类型,他们会看到以下错误:
error TS1127: Invalid character.
该错误的来源很清楚(#
印记),所以我的问题如下:
- 如果我在将库发送给客户之前对
index.d.ts
进行后处理并删除#private;
行,这样可以吗,他们不必了解实施细节?我可以通过使用ttsc
包轻松地做到这一点,但我仍然担心那条打字信息可能在某种程度上很重要。 index.d.ts
中#private;
行的实际用途是什么?为什么声明文件会暴露 class 使用私有字段,如果它们无论如何都无法访问,并且是实现细节?- 根据 a topic in Typescript Github issues,这是预期的行为,因此带有私有字段的 classes 在发送到
.d.ts
文件时保留其标称的键入行为。可悲的是,这种解释的意义从我身上溜走了。是否有任何我可以阅读的额外文档以更好地理解 Typescript 的名义打字行为?
#private 语法目前是 stage-3 proposal for javascript。一旦浏览器支持它,它就不会被打字稿转译。
它使类型成为“标称”类型,因此公开相同 public 成员的其他类型不被视为与具有私有字段的类型兼容。这很重要的一种情况是,如果您有这样的代码:
class C {
#foo = "hello";
bar = 123;
static log(instance: C) {
console.log("foo = ", instance.#foo, " bar = ", instance.bar);
}
}
我敢肯定还有更多示例,但这个静态方法只是我想到的一个。
此 C.log
函数需要 C
class 的实际实例,因为它访问 instance
参数上的私有命名实例字段。如果声明 emit 没有通过指示它具有 ES 私有字段来反映 C
类型是名义上的,而是仅发出 public 字段,则编译器将在此处使用结构类型比较并且不会' t 产生预期的类型错误。例如,该声明 emit 将允许依赖代码将 { bar: 456 }
传递给 C.log
而不会出现任何编译器错误。
我试图回答你的问题但无法回答,然后我出于好奇问了我自己的问题,这是由一位 TypeScript 贡献者回答的,你可以在这里找到他的答案:What's the purpose of #private in TypeScript definition files?
总而言之,在某些情况下,私有字段在比较类型时很重要,这就是 #private
字段出现的原因,因此“包含私有成员”的信息是类型的一部分定义。