Typescript: 实施私有领域提案

创建于 2016-07-26  ·  134评论  ·  资料来源: microsoft/TypeScript

我认为在 TypeScript 中实现第一阶段的私有字段提案会很好。 它将主要取代当前的伪私有实现,并且完全正确的实现只能使用每个类的 WeakMap 转换为 ES6。 我会注意到规范本身在内部使用 Wea​​kMaps 来对私有状态进行建模,这可能有助于实现提案。

目前,该提案仅包括私有 _properties_,但可能会遵循方法。 此外,该提案最重要的部分是私有属性仅在类本身内可用。

Committed Fixed Suggestion

最有用的评论

我认为人们不会对基于非“私有”关键字的解决方案感到满意。

所有134条评论

TypeScript 团队如何看待符号/字符前缀的语法和使用?

我个人认为它看起来很糟糕,但显然存在技术限制(用法需要确定可见性,原因我不完全理解)。

看到 TypeScript 失去了当前的私有/受保护语法,这将是令人难过的,因为它更清晰,并且与许多其他语言保持一致。 这有可能发生吗? 有没有其他选择?

除此之外,还有关于可能切换#@符号的讨论(即使用#作为装饰器),这显然也会对 TypeScript 产生影响.

我也觉得“太恶心了”。 我认为就像::绑定运算符一样,它实际上并没有让它走得很远,即使尝试实现它也值得推迟,直到它在 T39 的道路上走得更远。 我高度怀疑这将是一段艰难的旅程。 此外,我怀疑支持它的向下发射将相当困难,因为需要重写每个访问站点。

用法需要确定可见性,原因我不完全理解

主要是因为您需要在使用站点确定如何查找属性,因为它需要不同的查找算法,以便后代类可以重新使用相同的私有名称,而无需“知道”祖先私有属性。

建议语法的一个优点是您可以省略this而直接使用#field 。 此外,可以使用装饰器(https://github.com/tc39/proposal-private-fields/issues/32)交换印记,而是使用@ ,因此您将使用@field ,就像 Ruby 一样。 你是否仍然觉得这个语法丑陋?

我认为人们不会对基于非“私有”关键字的解决方案感到满意。

我没有看到一个很好的方法来做到这一点,同时像 JavaScript 那样支持通用的eval ——一个具体的令牌允许一些差异化,并使支持不基于静态类型系统的私有状态成为可能,如在 TypeScript 中. 我们已经在https://github.com/tc39/proposal-private-fields/issues/14讨论了许多语法替代方案,我不认为 TypeScript 的当前语法可以一直正常工作完全通用的 JS 环境。

主要是因为您需要在使用站点确定如何查找属性,因为它需要不同的查找算法,以便后代类可以重新使用相同的私有名称,而无需“知道”祖先私有属性。

我希望我能更多地了解 JavaScript 在内部是如何工作的。 我认为它会像这里这里描述的那样工作,但显然不是。 我仍然觉得很难相信这会对性能产生重大影响,但没有可比较的数字。

你是否仍然觉得这个语法丑陋?

基本上,是的。 更重要的是,我发现它既与 JavaScript 语法的其余部分不一致,也与许多其他语言不一致:

| 语言 | 语法 | 笔记 |
| --- | --- | --- |
| C# | 私有整数 x; | |
| C++ | 私人的:
整数 x; | |
| 爪哇| 私有整数 x; | |
| PHP | 私人 $x; | |
| 蟒蛇| __x | “没有意见” |
| 红宝石 | 私人的
定义方法
# ...
结束 | 这是一种方法,但字段是私有的
默认情况下我认为。 |
| 打字稿 | 私人 x; | |
| Visual Basic | 私有 x 作为整数 | |

除了 _one_ 之外的所有语言都使用private关键字,而且 Python 似乎并没有真正拥有“适当的”私有状态。

除了 Python 之外(再次),没有一种语言根据可见性格式化字段声明或字段访问,并且它们都允许在需要时使用新的可见性修饰符。

我也觉得#@都更适合装饰器之类的东西,它们(用凯文的话来说)“在语法上'在命令流之外'”。

我没有看到像 JavaScript 那样支持通用 eval 的好方法

是否有可能用外行的术语来解释这个问题? (也许在 https://github.com/tc39/proposal-private-fields/issues/14)

最好在一个地方列出这些问题和示例,以便可以参考。

我仍然觉得很难相信这会对性能产生重大影响,但没有可比较的数字。

如果你希望它是真正私有的,而不是像 TypeScript 那样的约定,它会这样做。 每当您在 JavaScript 中查找属性时,过程本质上是这样的:

  1. 查看自己财产的实例。
  2. 如果没有自己的财产,请查看原型以获取自己的财产。
  3. 上升原型链直到找不到属性。
  4. 如果找到处理属性描述符(可写、获取、设置、可配置)
  5. 如果未找到并读取,则返回undefined或写入,如果未密封或冻结,则将 value 设置为自己的属性。

现在,如果私有名称中没有模式,您将不会拥有自己的属性,您将拥有诸如自己的私有属性之类的东西,它们不会提升原型链。 然后,对于可能访问私有属性的每个操作,您还必须在那里寻找它们,因为您无法确定引用的是哪个。 以正常方式查找,然后仅在未找到的情况下查找私有版本可能会非常危险,因为如果您在原型链中找到了一些东西,但也有私有版本怎么办?

最大的挑战是 JavaScript 类仍然有点用词不当。 它们本质上是原型继承构造函数的语法糖。 我想到了一个想法,我将尝试将其添加到 tc39/proposal-private-fields#14。

是否有可能用外行的术语来解释这个问题?

如果它需要重新编写调用站点,那么您将永远无法支持以下内容:

class Foo {
    private foobar: string;
    baz() {
        const p = 'foo' + 'bar';
        console.log(this[p]);
    }
}

eval类的结构的任何用法。 您可以选择不支持诸如私有索引访问或不支持 eval 之类的事情,但是“为什么要麻烦”。 几乎所有这些都在那里的提案中以一种或另一种方式指出,但人们仍然“但我喜欢私密”😁。

你不会有自己的财产,你会有类似自己的私人财产的东西

如果您在描述符中有一组带有visibility项的属性,我想问题在于,如果当前对象上不存在该属性,您将不知道是否要提升原型链。

如果它需要重新编写呼叫站点,那么您将永远无法支持诸如...

AFAIK,无论如何都不会支持( ref )。

我仍然没有真正遵循 eval 案例。 我认为在计算属性名称之后,属性检查会在运行时进行。

但人们仍然是“但我喜欢私人”

我试图不成为这些人中的一员,并试图理解这些问题,但提议的语法让我感到不舒服。 =)

好的,我想我现在理解了 eval/rewrite 的情况。 类中的使用站点将被重写以指示基于声明的属性的可见性,除非它们是简单的查找,否则这是不可能的。

如果您在描述符中有一组带有可见性项的属性,我想问题在于,如果当前对象上不存在该属性,您将不知道是否要提升原型链。

唔。 但是如果它在当前类中不存在,那么它不是定义为非私有的吗? 如果是这样,它无论如何都必须向上移动原型链(与常规公共属性查找一样)。 private访问不会有额外的工作。

(我可能遗漏了一些明显的东西)

但是如果它在当前类中不存在,那么它不是定义为非私有的吗? 如果是这样,它无论如何都必须向上移动原型链(与常规公共属性查找一样)。

不,你不想提升。 私有标签不会被继承,子类可以重用私有标签而不必担心掩码/名称冲突。

@glen-84 您提到的这两篇文章都表明未签名的私有状态存在问题。 你有解决这些问题的想法吗? 我认为使查找链复杂化在兼容性方面存在风险,使 JavaScript 难以以良好的性能实现(可能使现有程序变慢),基本上不可能与代理一致,并且通常会显着使语言的心理模型复杂化(这已经有了一个比较复杂的对象系统)。

在跨语言比较中,您提到了 Ruby。 我认为 Ruby 是私有状态的一个很好的例子 _with_ a sigil -- @ 。 您可以在没有符号的情况下调用 getter 和 setter 方法。

不,你不想提升。 私有标签不会被继承,子类可以重用私有标签而不必担心掩码/名称冲突。

我的意思是如果该财产不在当前类别中,则向上移动以寻找公共或受保护的财产。

您提到的这两篇文章都表明未签名的私有状态存在问题。 你有解决这些问题的想法吗?

作为一个不了解 JavaScript 内部工作原理的人,我很难做到这一点。

You'd have to somehow encode a "private key" into each lexical environment.

我不知道这是什么意思。 它有什么用? 是不可能做到的吗?

You'd have to change the semantics of each and every property access (because any property access might result in a private field). Engines are highly optimized around the current property lookup semantics.

如此高度优化,以至于单个可见性开关会显着影响性能?

Would for-in enumerate over these properties?

我想这将取决于上下文。 在同一个班级,是的。 然而,这不是不使用private ,这是一个实现细节,其他语言可能已经回答了这样的问题。

Can someone shadow a private property with a normal property lower on the prototype chain? What about the reverse?

第一个问题可能是(可见度增加),第二个问题可能是否。 再说一遍,这一切以前都做过,不是吗?

How do you prevent leaking the names of private fields to clients that shouldn't know that information? This is probably a fatal information leak.

可见性只是封装和定义公共接口的工具。 99% 的开发者可能并不关心“信息泄露”。 也就是说,我确实在这里建议了两个单独的功能。 也许这个提议可以被称为不同的东西,比如“隐藏状态”或“安全状态”,并允许以不同的方式实现诸如私有/受保护状态之类的东西。

All of this runtime stuff is going to be terrible for performance

如果您想要性能,请使用“隐藏/安全状态”。 :D 严肃地说,我们在谈论什么类型的性能损失? 也许有人可以创建一个原型。 =)

Also, we couldn't use such a solution to self-host the built-ins

自托管内置插件(如果我什至明白这意味着什么)不会对性能真的很不利吗? 如果不是......使用“隐藏/安全状态”而不是更高级别的私有/受保护可见性。

我认为使查找链复杂化在兼容性方面存在风险

我不是第一个/唯一一个认为这就是它可以/可能如何工作的人。 您访问一个属性,它会查看描述符以获取可见性,并相应地做出响应。 如果您不知道 JS 中的实际工作原理,这似乎并不复杂。 我真的需要阅读有关 JS 内部/属性查找算法的速成课程。 =P

我认为 Ruby 是带有印记的私有状态的一个很好的例子--@

Ruby 甚至不是 C 族语言,而且似乎没有公共字段,只有 getter 和 setter(访问器)。 当前的私有状态提案有多个并排放置的声明,具有相同的通用目的(声明属性),但语法明显不同且不一致。

尽管如此,我在这里已经超出了我的深度,而且我很可能会增加更多的噪音而不是价值,所以我会尽量保持安静,让专家达成共识。

我将与 TC39 讨论这个愿望,我们将看看我们是否可以提出关于如何避免前缀的任何其他想法。 我个人没有。 请注意,如果 TypeScript 确实决定实现私有字段,它们在 TC39 中仍处于第 1 阶段,因此可能会发生变化。

TypeScript 团队如何看待符号/字符前缀的语法和使用?

我个人认为它看起来很糟糕......

注意我提出了一个建议来摆脱令人敬畏的#语法。

@shelby3不幸的是,我认为这不是一个现实的选择。 tl;dr,我们必须担心一切将如何与eval交互; 不包括印记只会使一切“太动态”而无法正常工作。

@littledan我现在已经跟进了,并提出了反对使用 sigil 的最有力论据,并提出了最大化与 TypeScript 兼容性的论点。 我现在明白为什么我们必须为方法的无类型参数声明隐私。

@isiahmeadows

它将主要取代当前的伪私有实现 [...] 此外,该提案最重要的部分是私有属性仅在类本身内可用。

我希望它不会取代伪私有实现。 我认为只有在一个班级内的可用性实际上并不是一件好事(鉴于可用性是指可访问性)。 我承认在某些特殊情况下,拥有严格私有且不可访问的属性是有意义的,例如出于安全目的。 我也承认,对于熟悉其他语言的人来说,这显然令人困惑, private实际上在 JavaScript 中并不是那么私密。 但除了安全原因,在我看来,大多数开发人员应该在大部分时间使用private只是为了定义合同而不是控制可访问性。

例如,从建筑师的角度来看,我认为关于 TS private关键字及其伪私有性质的一个非常好的事情是

  • 它允许表达类型接口的契约以及客户端如何使用它
  • TS 编译器在编译时检查合约
  • 我仍然可以在运行时有意识地“违反”合同,特别是对于白盒单元测试。

运行时私有属性的可访问性非常有助于可测试性,因为我可以通过设置私有字段将私有状态注入到被测类中(在 TypeScript 中,我建议使用括号表示法而不是any强制转换,因为这样更好重构支持),例如:

let instance: ClassUnderTest = new ClassUnderTest();
instance["_privateField"] = "My injected state";

无需复杂的测试代码即可设置具有特定(私有)状态的类。
伪私有属性的另一个优点是它们对于猴子补丁来说是必不可少的。

我不认为 TypeScript 社区会高兴地将他们所有的private variable行更改private #variable

从 TypeScript 的角度来看,我们大多数人都对我们对一门好语言(智能感知、构建时错误、类型、各种糖)的可爱、甜蜜的幻想感到满意。 这些幻想给了我们更好的开发体验,我们更快地编写更好的代码。 这是除了 ESNext 转译之外我们还使用 TS 的主要原因——但对于后者,有 Babel 并且更好(或者至少在我上次检查时更好)。

我不是在谈论那些实际上想要从私有变量中获得更多东西而不是源文件中的语法糖的少数人。 我认为那些人需要更强大的东西,也许更接近本机代码。

但对于我们其他人:我们真的不需要 JS 私有。 我们需要简单易用的private convenient变量,就像我们在 C++、Java、C# 等中使用的一样。

请投票支持一个不会给我们带来痛苦的解决方案。 也许软私人? 因为我怀疑我们是否想要私有的 sigil #variable 。 或者也许 TS private和 ES private 是不同的概念? 丑陋的。

@igabesz

我不认为 TypeScript 社区会高兴地将他们所有的private variable行更改private #variable

实际上,有了这个提议, private就没有必要了。 取而代之的是, #印记完全没有冲突地取代了它。

但对于我们其他人:我们真的不需要 JS 私有。 我们需要简单易用的私有变量,就像我们在 C++、Java、C# 等中使用的那样。

TypeScript 的私有是软私有的,就像大多数 OO 语言一样。 甚至 Java 的私有变量在技术上仍然是软私有的,因为它们仍然可以通过逃逸舱门访问。 JS 私有等同于使用闭包,除了您仍然可以访问非this实例的私有状态。

请投票支持一个不会给我们带来痛苦的解决方案。 也许软私人? 因为我怀疑我们是否想要标志私有的#variable。 或者也许 TS private 和 ES private 是不同的概念? 丑陋的。

它们是不同的概念,但总的来说,逃生舱口在实践中很少有用。 主要的例外是对象检查(例如开发人员工具,Node.js util.inspect ),但大多数是主机定义的并且现在已经使用了特权本机 API,因此没有迫切需要将其添加到规范中。

此外,一旦 ES 具有标准化的私有状态,TS 将采用它并可能弃用其自己的软私有机制,将在下一个主要版本中删除。 它一直是 ES 的严格超集,并且随着 ES 本身的发展,它根据需要添加(异步函数)、更改(类)和/或弃用( /// <amd-dependency /> )功能,以保持自己作为一个严格的超集而不是复制当前规范。

此外,一旦 ES 具有标准化的私有状态,TS 将采用它并可能弃用其自己的软私有机制,将在下一个主要版本中删除。

😭

此外,一旦 ES 具有标准化的私有状态,TS 将采用它并可能弃用其自己的软私有机制,将在下一个主要版本中删除。

这不是TS团队的立场。 我们没有计划在短期内弃用任何东西。
如果当私有状态提案达到正确状态时,TS 将实施它。 我认为这对私人没有任何影响,因为 TS 今天实施了它们。

@mhegazy好的。 我站着纠正。 (这是一个有根据的猜测,顺便说一句。)

类字段提案现在处于第 2 阶段,所以我很高兴 TypeScript 团队考虑到这一点并准备遵循 EcmaScript 标准💯

如果当私有状态提案达到正确状态时,TS 将实施它。

@mhegazy第 3 阶段是实施的正确时间吗?

编辑:我可能已经找到答案了😄

@styfle请参阅设计会议笔记 (#16415) 中的讨论,该讨论讨论了当前关于实现的注意事项。

第 3 阶段是实施的正确时间吗?

是的。 我们开始研究此功能可能的不同设计。

Class Fields 提案现在处于第 3 阶段。 (截至一个月前)

当类字段达到第 3 阶段时,私有方法和访问器紧随其后,一直处于第 2 阶段,直到昨天移至第 3 阶段。现在处理类私有成员所需的一切都在第 3 阶段。

TS 团队在采用#[field]语法方面的立场/进展有任何更新,因为它已经处于第 3 阶段一段时间了吗? 我个人非常不喜欢它,更喜欢 TS 现有的private关键字,但同时希望尽可能接近标准。

我个人非常不喜欢它,更喜欢 TS 现有的私有关键字

我也是,好丑

但是@mhegazy我想(尝试)这样做,可以吗?

解析应该不错(几乎是一个新的修饰符,几乎只是一个标记),但是类型检查会很痛苦(因为我们将有两种不同类型的私有属性,需要以某种方式进行比较),并且downlevel 发出是非常糟糕的(因为降级真正的运行时隐私是一个很大的转变—— @rbuckton 对此有想法,也许还有一个实现(我不确定;他的叉子里有很多))。 从技术上讲,我们无法阻止您尝试,但我不会推荐它,如果您能找到其他更愿意尝试的东西,我不能保证一旦您完成,我们就准备好接受它。 另外,虽然私有字段和方法已经进步,但在私有静态(可能还有装饰器)也进步之前,它仍然有点不完整(考虑到它们如何交互,最好一次添加它们)。

我只想说,这里有很多。

@weswigham好吧,我放弃了😂

这是我(与@Neuroboy23和其他人)将尝试实现私有字段的提示。 一旦有材料可供审查/讨论,我们将在此处发布链接。

更新:我们正在进行的工作在这里

是的。 我们开始研究此功能可能的不同设计。

我也不喜欢#语法,但我理解这种语法背后的技术原因。 @mhegazy在实施一项新提案后,我真正想由 TypeScript 团队做什么,以思考 TypeScript 将如何处理诸如namespaceprivate类的过时实现,这些实现可以使用但通常应该不是因为有更好的 es-standard 方式来做相同或几乎相同的事情。

我还想加上我关于protected几美分。 如果(现在希望)我们有一天要删除/弃用private关键字,我认为对protected关键字也可以这样做。 我知道大多数人可能不同意,但是是的,额外的可见性范围有时会很方便,但恕我直言,它的整体价值并不高。

@pleerock

这是我希望从 TypeScript 中看到的:

class Example {
    private a = 1;
    #b = 2;
}

发出(针对 ESNext):

class Example {
    a = 1;
    #b = 2;
}

Emit(针对 ESNext,带有新的编译器选项以发出标记为私有的字段为 ES 私有字段):

class Example {
    #a = 1;
    #b = 2;
}

这应该是向后兼容的,同时还允许您使用具有干净语法的 ES 私有字段。

@glen-84 当然会,我说的是关于过时关键字和语法的长期计划

我们不打算弃用任何语法或关键字。

我也不认为我们将有任何形式的选项将private转换为# - 它们具有不同的预期行为; #是硬运行时隐私,而private只是设计时隐私。

@weswigham我也这么认为。 @RyanCavanaugh是的,这是预期的答案。 但是我仍然会为新用户应用至少一些策略来避免使用命名空间/私有关键字,因为恕我直言,他们已经过时了最新的 ecmascript 提案

人们通常根据阅读文档来解决这个问题,我们当然会更新这些文档。 module foo {仍在该语言中,但除了在namespace foo {之前的非常旧的代码库中之外,基本上再也没有出现过。

@RyanCavanaugh很高兴听到这个消息。 但我仍然相信来自 c# 的新人肯定会尝试使用命名空间(不是全部,而是其中一些)。 我想来自其他语言的用户可能也是如此 - 他们将开始使用 private 而不是#并且这往往比使用命名空间的示例更大

我也不认为我们有任何类型的选项可以将私有转换为 # - 它们具有不同的预期行为; # 是硬运行时隐私,而私有只是设计时隐私。

哦。 我希望我们也可以选择将private用于硬隐私,以避免......不幸的语法。

无论如何,对于我的(当前)用例来说,软私有可能就足够了。

我认为在即将推出的 TypeScript 3 版本中包含此语法支持会很棒,因为此功能非常强大,并且版本 3 看起来是让人们开始使用新的#语法的好机会。

编辑:该死的忘记版本 3 已经发布了。

仅供参考,最近有一些关于私有字段/插槽/TC39 提案回购中的任何内容的变动,因此甚至不确定当前形式的提案是否会成功。 这里有几个相关的问题:

我不是TC39,但我个人给大家的建议是,先等语法再次固化(可能要等到stage 4),然后再实现。

FWIW 我不会将 tc39/proposal-class-fields#100 中的讨论解释为任何特别的指示。 #乍一看并不漂亮,但没有建议更好的语法形式,人们似乎想要的唯一语法显然是行不通的。 需要有某种前缀印记,所有允许this.someProp私有的尝试都注定要失败。

我意识到这听起来相当不屑一顾,但坦率地说,这是我的意图 - 这些线程中的抱怨者都没有有意义地参与现有线程或常见问题解答中解决的核心技术问题。 通读该存储库上的线程并看到有关为什么需要印记的正确解释被否决了,这真是令人沮丧。

如果最终结果是没有人使用私有字段,除非他们确实需要严格的运行时隐私,那么就性能和可调试性而言,这对网络来说可能是一个很好的结果。

我同意这可能不是一个理想的问题,但另一个,
tc39/proposal-class-fields#106,可能更具指示性 - 有
认真讨论使用弱映射代替其他事物,因为
代理互操作显然很糟糕。


以赛亚草甸
[email protected]
www.isiahmeadows.com

2018 年 7 月 30 日星期一下午 3:38,Ryan Cavanaugh通知@ github.com
写道:

FWIW我不会解释讨论
tc39/proposal-class-fields#100
https://github.com/tc39/proposal-class-fields/issues/100
特别说明任何事情。 # 乍一看并不漂亮,但
没有建议更好的语法形式,唯一的语法
人们似乎想要的显然是行不通的。 必须有前缀
某种符号以及所有允许 this.someProp 私有的尝试
注定要失败。

我意识到这听起来相当不屑一顾,但坦率地说,这就是我的意图——
这些帖子中的投诉者都没有有意义地参与
现有线程或常见问题解答中解决的核心技术问题。 它是
令人沮丧的是阅读该存储库上的线程并看到很长的时间
为什么需要印记的正确解释被低估了
地面。

如果最终结果是没有人使用私有字段,除非他们真的
需要严格的运行时隐私,这对网络来说可能是一个很好的结果
性能和可调试性方面。


你收到这个是因为你被提到了。
直接回复本邮件,在GitHub上查看
https://github.com/Microsoft/TypeScript/issues/9950#issuecomment-408984395
或静音线程
https://github.com/notifications/unsubscribe-auth/AERrBGCphyQUu5lJQW7lgsqALLL3e0_Wks5uL2DLgaJpZM4JVDwV
.

有一些关于使用 Wea​​kMaps 的讨论,但我看不出这将如何改善与 Proxy 的交互。 我会邀请任何对私人课程功能应该如何工作有其他想法的 TC39 成员将其提交给委员会以获取反馈; 目前,该提案处于第三阶段,理论上代表了委员会的共识立场。 许多人做出妥协以实现启用此功能的共同目标,即使其他设计也是可能的。

我正在努力组织框架之间的讨论,讨论如何使用 Proxy 观察对象突变,以及它应该如何与私有字段交互。 如果您想加入对话,请告诉我。

@瑞安卡瓦诺

FWIW 我不会将tc39/proposal-class-fields#100 中的讨论解释为任何特别的指示。 #乍一看并不漂亮,但没有建议更好的语法形式,人们似乎想要的唯一语法显然是行不通的。 需要有某种前缀印记,所有允许this.someProp私有的尝试都注定要失败。

迟到了,但实际上有一个提议建议this->var语法

当然,这个提议很可能已经死了(“委员会没有热情”是我能找到的唯一原因)。 但是确实有人提出了替代语法,我希望所有感兴趣的人都熟悉并了解这些。

我认为有一个编译器选项可以让private转换为某种在运行时强制执行的 _soft_ private 会很好。 我不认为需要真正的 hard private 的用例特别常见,所以即使不喜欢#语法,我认为大多数人都会倾向于坚持使用private 。 但是编译时只有私有是_too_软IMO。 此外,这样的选项将有助于减少可能的私有变体的数量……如果让开发人员自行实现这一点,那么您可以拥有所有这些:

class Demo {
  private a

  #b

  <strong i="9">@reflect</strong>
  #c
}

因此,我建议启用新选项后, private a将转换为<strong i="13">@reflect</strong> #a ,其中@reflect是一个装饰器,可以通过社区支持的 API 对属性进行反射。 有一些关于标准装饰器库的讨论,因此@reflect装饰器(或我们想称之为的任何名称)在未来可能会被标准化; 我认为这将是一个很好的候选人。

我想我的提案的主要缺点是对性能的影响。 我们希望有一天 JS 可能有一些标准的装饰器可以在本地实现来优化它们,但在可预见的未来,现实是<strong i="19">@reflect</strong> #x会比#x慢。 但我只是建议将此作为一个选项,默认情况下可能应该禁用(出于向后兼容性的原因)。

@MichaelTheriot

迟到了,但实际上有一个建议建议 this->var 语法。

当然,这个提议很可能已经死了(“委员会没有热情”是我能找到的唯一原因)

委员会给出了很多深思熟虑的理由来支持当前的提案而不是 1.1 类提案,例如https://github.com/tc39/proposal-class-fields/issues/100#issuecomment -429460917

@mbrowne

我可能错过了。 class 1.1的issues页面已经半年没活动了,连你链接的例子也是我评论一个月后写的。

仅供参考,我在几个月前您链接的线程中提到了这一点。 我在这里的评论只是为了解决一个误解,即没有提出替代语法,因为我相信所有相关方都应该意识到情况并非如此。

编辑:我的评论并不建议 TypeScript 做任何不同的事情。 我认为纠正有关提案参考问题的错误信息很有用。

@MichaelTheriot需要被告知替代方案的当事方不是本次对话所涉及的当事方。 TypeScript 将遵循即将获得批准的提案。 在我看来,替代语法已被提出但未被采用这一事实对本次对话并没有真正有用。

嘿伙计们,如果有帮助,我想分享我自己的运行时保护/私有成员实现:

lowclass

查看大量测试文件,显示运行时公共/受保护/私有成员的各种用途。 实现时间不长,可以省略一些功能,以便仅具有最小的受保护/私有功能。

笔记:

  • 它使用 Wea​​kMaps 来存储受保护/私有状态。
  • 与我见过的其他实现不同,它使用带有回调/承诺/等待的异步代码,因为它不依赖于同步调用堆栈跟踪。
  • 它适用于 getter/setter(包括超级调用)(参见测试)。
  • 与原生super使用,或使用 ES5 的Super助手(请参阅测试)。
  • 支持constructor方法(见测试)。
  • 能够扩展内置类(Date 除外,但我想研究一下,尽管人们说这是不可能的,但我想确认一下。请参阅测试,fe 使用本机自定义元素)。
  • 能够扩展常规本机class es(请参阅测试)。
  • 包装本机class es,为它们提供受保护和私有的能力(参见测试)。
  • 编写 ES5 风格的function类而不是原生的class es(参见测试)。
  • 大量的性能优化空间(fe 缓存超级/受保护/私有帮助程序调用和优化查找算法)

运行测试:

npm install
npm test

另请参阅https://github.com/babel/proposals/issues/12https://github.com/babel/babel/issues/8421以了解 Babel 实现的详细信息和问题。

大家好,

请不要实现尚未最终确定的私有类字段规范。 它有问题。

请阅读此线程

我会鼓励任何阅读本文的人查看一些其他语法想法(只需仔细阅读,还有更多),并发表您的意见。

fe 这是另一个线程(比当前的#恕我直言,具有更好的语法思想)。


如果有任何 JavaScript 社区已经广泛使用 public/private/protected,那么 TypeScript 社区很有可能帮助塑造 JS private/protected 的未来。

因此,私有类字段将在 V8 v7.2 和 Chrome 72 中发布。是否有任何计划开始实施私有字段提案?

@ChrisBrownie55公共字段正在发货。 私人不是。

@jhpratt那是我的错,但似乎 Chrome 团队正计划在不久的将来私下发货

供参考: https: //v8.dev/blog/v8-release-72#public -class-fields

它记录了他们从 V8 7.2 开始传送公共类字段,但有关于私有字段的内容(重点是我的):

计划在未来的 V8 版本中支持私有类字段。

@isiahmeadows我实际上指的是 Google 开发者博客上的另一篇文章。

Screenshot of Google Developers page

结论

公共类字段在 V8 v7.2 和 Chrome 72 中提供。我们计划很快提供私有类字段。

链接到 Google 开发者博客上的文章

这些文章由@mathiasbynens和 Andreas Haas 撰写,如果需要,您可以要求澄清(尽管我认为这些帖子中的每一个都非常清楚)。 cc @gsathya@joyeecheung正在对 V8 中的实现进行收尾工作。

无论如何,2019 年 1 月的 TC39 会议结束了一年半重新思考私有领域和方法提案的替代方案,再次重申了对提案的共识。 我认为我们可以考虑当前版本稳定并准备好使用 TypeScript。

Chrome 刚刚发布私有类字段 🎉
它们仅在当前在 _canary_ 版本中发布的 Chrome 74 中。

screenshot of tweet

我刚刚在 Chrome 74 中发布了私有类字段! 立即在 Chrome Canary 中试用它!
— Sathya Gunasekaran 通过 Twtiter

有谁知道我们在为私有类字段选择特定实现(或构建一个)方面处于什么位置? 我看到@trusktr推荐了lowclass,但我不知道“_Private Inheritance_”是否是规范的一部分。

绝对不是; 私有字段不走原型链(因为其他对象将能够看到它们,因此它们不会是私有的)

我假设私有字段将转换为 WeakMaps(每个字段一个 WeakMap,与 Babel 的做法相同)。 对于那些专门针对支持它的浏览器的人来说,还应该有一个选项可以在最终输出中保留#语法(这当然会随着时间的推移变得更加相关)。

出于性能原因,可能还值得考虑一个选项,允许开发人员使用#语法以实现未来的兼容性(当更多浏览器支持它时),但实际上转换为具有一些特殊前缀的公共属性,例如__ts# 。 WeakMaps 应该进行基准测试,看看这是否真的有必要,但我怀疑公共属性和 WeakMaps 之间的性能差异可能很大。 如果添加了这样的选项,它当然应该默认关闭,因为使用#语法的开发人员通常会期望它在编译时和运行时都是私有的。 但是对于那些想要最大化运行时性能并且同时满足于编译时私有的人来说,这可能是一种开始使用新语法而不会导致性能下降的好方法。

有关实施进度的任何更新? 也许我们可以建立一个 PR 来测试并提供反馈?

@jhpratt肯定! 如果您查看此 PR 中的分支,您将能够测试私有命名的实例字段。 方法和访问器正在进行中。

我们希望上游这项工作。 合并此先决条件 PR 后,我们可以立即针对此存储库 (Microsoft/TypeScript) 发布更改: https :

非常欢迎反馈。

我不知道“私有继承”是否是规范的一部分。

旁注,我计划在低级中删除该功能,以实现 100% 真正的隐私。 我在实践中并没有真正需要它,它更像是一个实验。

顺便说一句,我想在这里发帖,以防任何关于“私有继承”的理论可能有任何用处(也许只是有趣,或者可能有助于激发任何​​其他想法):


如果你有兴趣:

“私有继承”(如当前版本的lowclass 所示)意味着子类可以使用从超类继承的私有方法,但该方法将更改__应用于_在该子类范围内的实例的私有属性_,就好像子类在其自己的定义中将这些方法定义为私有方法,但子类不能在超类或兄弟类范围内修改实例的私有属性。

相比之下,在“保护继承”中,子类_可以_修改其自身实例或超类实例的属性,但仍然不能修改兄弟类的属性。 在受保护的继承中,子类修改所有超类都能看到的属性(超类都读/写这些相同的属性)。

换句话说,在“私有继承”概念中,每个类都有一个私有作用域,任何继承的私有方法都只在本地类作用域上操作,而protected 则相反,protected 方法在整个类层次结构的单个作用域上操作。

不确定这是否有意义,所以这里有一些简单的代码示例来解释什么是“私有继承”,如果我们使用当前的 ecma proposal-class-fields 私有字段特性来编写它:


示例代码更容易理解:

提案类字段中没有“私有继承”,因此以下内容不起作用(我同意这是可取的,以维护真正的隐私):

class Foo {
    test() {
        this.#privateMethod()
    }

    #foo = 'foo'

    #privateMethod() {
        console.log(this.#foo)
    }
}

class Bar extends Foo {
    test() {
        // This does not work, no private inheritance:
        this.#privateMethod()
    }

    // #foo is private only inside Bar code, it is NOT the same #foo as in Foo
    // scope.
    #foo = 'bar'
}

在lowclass中,“私有继承”相当于编写以下非DRY代码来模拟相同的事情,在编辑器中使用一些复制/粘贴:

class Foo {
    test() {
        this.#privateMethod()
    }

    #foo = 'foo'

    #privateMethod() {
        console.log(this.#foo)
    }
}

class Bar extends Foo {
    test() {
        // This does not work, no private inheritance:
        this.#privateMethod()
    }

    // #foo is private only inside Bar code, it is NOT the same #foo as in Foo
    // scope.
    #foo = 'bar'

    // copy the method over by hand (because there's no private inheritance):
    #privateMethod() {
        console.log(this.#foo)
    }
}

在这两个示例中, #foo变量是每个类的特定变量。 有两个#foo变量,不是一个; 每一个都只能由同一类定义中的代码读取和写入。

在lowclass中,私有继承允许我们重用私有超类方法, _但是#foo变量。

在lowclass中,如果超类中使用了#someMethod则对超类的#foo进行操作。 如果在子类的作用域中使用了#someMethod ,它对子类的#foo进行操作,而不是对超类的#foo进行操作!

我希望这能解释这个概念,即使它不会被使用,我希望它可能对激发任何类型的想法很有趣或有用。

它现在在 Chrome 稳定频道中,因此开发人员可以在本地使用它。 由于 VSCode,我对这个问题最感兴趣 - 在编写 vanilla .js javascript 时,VSCode 将其标记为错误。 有没有办法在 VSCode 的 Vanilla JS 中添加对私有类字段的支持,而不是关于是否将它们添加到 Typescript 的争论?

就我个人而言,我认为 TS 不应该在达到第 4 阶段之前添加对它们的支持。TS 已经有编译时私有的,现在工作得很好。 在它进入第 4 阶段后,我会同意这是有道理的。 (讨论中也偶尔会有一些变化,所以我仍然认为它没有准备好迎接黄金时段。)

更新:Node 12 稳定版也支持它。 此外,Babel 有一个插件来转换这种语法。 开发人员经常在功能成为第 4 阶段提案之前使用它们。 我希望看到在 Vanilla JS(非 ts)中添加对此语法的支持或通过jsconfig.json启用它的方法,以便 VSCode 在使用它们时不会显示错误。 VSCode repo 说他们的 JS 支持得到了 TypeScript 的支持并提到了这个问题。

我不得不说,TypeScript 根本不支持该功能是没有意义的,因为它已经存在于主要浏览器和 Node.js 的生产环境中。 这并不是说 TypeScript 必须立即完全巩固所有内容并将其作为默认功能发布。

我建议 TypeScript 在一个标志下引入私有字段,表明此功能是实验性的,并且在第 3 阶段和第 4 阶段之间可能会发生变化。

也许我们可以在没有语义的情况下先实现语法支持?

也许我们可以在没有语义的情况下先实现语法支持?

对于类型检查/智能感知,我认为必须有某种语义,但不能没有像BigInt这样的下层转换支持(只能与esnext )。

fwiw,由于实施反馈,它只会在第 3 阶段发生变化。 鉴于 chrome 正在运送它,任何改变都是极不可能的。

@ChrisBrownie55我想说这个功能还没有实现没有任何意义

看起来这是在进行中:
https://github.com/microsoft/TypeScript/pull/30829
(显然正在等待 https://github.com/microsoft/TypeScript/pull/30467)

是的,#30829 即将在 rebase 后准备合并,对我们可能想要做的一些特征门控取模,因此它会在私有命名方法上爆炸。

伙计们,仅仅因为一个主要的浏览器实现了这个功能(看看它的感觉,玩它等)并不意味着每个人都应该这样做。

讨论中也偶尔会有一些变化,所以我仍然认为它没有准备好迎接黄金时段

正如@isiahmeadows提到的,class fields 提案充满争议,很多人不喜欢它。 以下是一些表明社区不喜欢当前私有字段的问题:

如果我是语言实现者,我会担心这一点,而且我不想为发布(一成不变)一个非常不受欢迎的功能负责,因为我决定允许成千上万(不知情的)开发人员开始使用有问题的生产代码中的功能。

私有字段可能是自 ES6 以来引入的所有特性中最具争议的。 我认为语言实现者在帮助确定功能之前考虑不喜欢是明智的。

@trusktr这可能是一个有争议的功能,但开发人员是否使用它应该由开发人员决定,而不是由工具决定。 一个主要的浏览器发布它不是为了“玩它”,而是为了在生产中使用它。 它还在最流行的服务器端 JS 运行时 Node 中发布。 再说一次,我不太关心语法是否适用于 TypeScript,而是更关心 VSCode(由 TypeScript 支持)上的 JavaScript 语言服务器是否支持该语法。

它也已在 Node 中发货

仅作为 Chrome 版本的一个副作用,它维护了 Node 的 JS 引擎。

它可能是一个有争议的功能,但开发人员是否使用它应该由开发人员决定,而不是工具

对于像您这样的开发人员来说可能就是这种情况(也许您只需要发布一个产品,并且您将使用您拥有的任何工具,这实际上是您在这方面应该做的,以及许多受雇开发人员所做的)。

也有许多开发人员可能不知道与类字段相关的脚枪,而只是尝试使用提供给他们的工具。

还有一些开发人员关心语言本身,以及可维护代码的未来,并希望看到它正确发展,以免某些错误为时已晚而无法消除。

好消息是,因为新的私有字段使用#语法,所以仍然有空间使用private关键字作为替代来修复它。

TS真的要100%按照标准吗? 我们已经知道委员会正在用thisGlobal#privateLol反对社区,所以也许是时候说谷歌在为时已晚之前没有垄断 JavaScript 了?

@TeoTN私有字段不是 Google 的东西。 它已经通过了 TC39,就像其他最近的标准一样。

有助于提供清晰的几点:

  • 我们并不急于发布尚未完全成熟的 ES 功能(另请参阅:可选链、空合并、抛出表达式、管道运算符、nameof 等)
  • 相反,实现已批准和交付的 ES 功能不是可选的
  • 很多人不喜欢某些东西都不是一个因素
  • 当我们相信我们可以安全地实施而不会导致严重的用户痛苦的后期设计更改(或撤销)时,私有字段将在 TS 中

@RyanCavanaugh感谢您的澄清以及所有

私有领域可以说是完全出炉了。

@kkimdev第 4 阶段已经结束; 这意味着已经成为标准的一部分。

尚未完全成熟的 ES 功能

好奇,什么是完全烘焙的 ES 功能? 在这个例子中,“完全烘焙”是什么意思?

实施已批准和交付的 ES 功能不是可选的

考虑到 TypeScript 的目标是简单的类型而不是 vanilla JS,这是完全合理的(因此namespace类的东西对于当前目标来说是一个糟糕的选择,而enum也是有争议的)。

通过等待(或不等待)发布功能,直到所有主要引擎都一致发布给定的功能,TypeScript 有一定的力量来帮助(或不帮助)社区在摇摆不定的语言规范中。

似乎效率低下,因为 TS 团队成员坐在 TC39 上,所以在任何人首先发布它之前,他们就已经成为第 3 阶段功能的共识的一部分——包括这个。

我真的很看重 TypeScript 的设计决策,因为它们在发布的内容上是保守的; 在许多情况下,等待一段时间以保证开发人员的稳定性是有意义的。 我对有关私人领域的政策决定感到非常满意,并经常与@DanielRosenwasser联系。 多年来,TypeScript 团队向 TC39 提供了许多有用的反馈,这有助于塑造许多功能的设计。

我认为讨论这些语言设计决策的最佳场所是提案存储库、TC39 会议以及致力于这项工作的其他上下文。 我们在那里与@trusktr广泛讨论了私有领域和方法提案; 这里的讨论似乎离题了。

最终,我认为 TC39 是我们应该继续进行语言设计的地方,而 TypeScript 存储库可以是讨论其他方面的地方,例如功能的优先级和实现细节,以及功能何时出现的判断稳定到可以发货。

由于 TypeScript Intellisense 支持 VS Code 中的 JavaScript 语法突出显示以及我在 VS Code 存储库中发现的两个语法突出显示问题(Microsoft/vscode#72867 和 Microsoft/vscode#39703),因此请在此处重定向 - 在这里讨论了在 TypeScript 中的实现 -让我贡献一下,如果这不是 JavaScript 文件中的错误会很酷。

完全有效的 JavaScript 在 VS Code 中被标记为错误,因为不同语言的编译器正在决定是否支持该语法。 :-)

我对 TypeScript 在做出决定之前花时间没有任何问题(事实上我支持它!),但这会影响 JavaScript 语法高亮显示,这种方式即使在本地也不容易修复或工作(就我知道)通过修补语法荧光笔语法文件,因为没有修补(AFAIK)。

虽然我不是 TypeScript 团队的成员,但他们正在积极致力于实现这一点,我认为在这一点上不会有太多的疑问,即私有字段将得到支持。 请参阅https://github.com/microsoft/TypeScript/pull/30829。

我可以确认它正在处理中 - 我们正在与 TS 团队合作,目前正在完成 rebase。 对 TS(以及语言服务器)中的私有命名字段感到兴奋。

非常感谢我们在彭博社的合作者在https://github.com/microsoft/TypeScript/pull/30829 中实现这一点

嘿。 如果您希望我为此创建一个单独的问题,请说出来。 我有兴趣了解发出导致#private PropertyDeclaration的基本原理是什么。

例如,将生成以下声明:

// index.d.ts
declare class Foo {
    #private;
    // ...
}

...给定输入:

// index.ts
class Foo {
    #name: string;
}

我试图首先理解为什么它需要在那里,但如果我正在围绕声明的生成构建工具,那么它是否可以被排除在外。

我试图首先理解为什么它需要在那里,但如果我正在围绕声明的生成构建工具,那么它是否可以被排除在外。

在我们的分析中,private 的存在使类名目化,因此在声明文件中保留它很重要。 您也许可以使用像dts-downlevel这样的 post-emit 声明转换器工具来以某种方式降低旧 TS 的私有声明的级别? (我不知道它是否有 #privates 的下层)

补充一下 Wesley 所说的:downlevel -dts将 #private 转换为private修饰符,以便与旧版本的 TypeScript 兼容。

在我们的分析中,private 的存在使类名目化,因此在声明文件中保留它很重要

你能详细说明它是如何使班级名义上的吗? 🙂 给定多个私有属性, #foo#bar ,仍然只有一个特殊的#private环境声明会被添加到声明中。 无法从声明中分析私有属性的名称和数量,因为它们都被替换为单个#private属性声明。 如果保留名称#foo#bar我会更好地理解它。 这有点奇怪,特别是考虑到 LanguageService 抱怨从未使用过#private属性。 对我来说这看起来像是一个错误。 但是在所有情况下,私有字段都不是类型的公共属性的一部分,并且不能从类外部访问,所以理论上我不明白为什么它们需要成为声明的一部分? 对于用其他访问修饰符而不是public注释的字段和方法,它们不是KeyOf类型而不是环境声明的一部分,不应该适用相同的原则吗?

补充一下 Wesley 所说的:downlevel -dts将 #private 转换为private修饰符,以便与旧版本的 TypeScript 兼容。

听起来是个不错的解决方案。 但是,通过这样做,您赋予private修饰符的任何属性都不会成为.d.ts文件的一部分,因为它不是该类型的公共属性的一部分。 我对声明特别感兴趣,即使使用最简单的示例,它也会为名为#private的未使用属性生成诊断信息。

@wessberg报告了您注意到的关于不需要的语言服务警告

回复你的另一个问题:

你能详细说明它是如何使班级名义上的吗?

之前有人打开了一个问题

在这些情况下做一些名义上的一个原因是为了让类的实现者可以在私有字段中保持一些隐藏的不变性:使类型结构化会破坏这个目标,至少没有真正花哨的类型可以表达“列表是始终排序”或“直径为 2 * 半径”。

另一个原因是像下面这样的代码应该无法进行类型检查,因为它无法在运行时“做正确的事情”:

class A {
    #foo = getFoo();
    bar = "bar";
    equals(other: A) {
        return this.#foo === other.#foo && this.bar === other.bar;
    }
}

new A().equals({ bar: "bar" }); // error: missing property '#foo'

嘿伙计们,我很兴奋我们有#private语法! 这很棒!

但我必须承认我真的很沮丧我们没有速记语法(请参阅提案) ,如下所示:

class Counter {
  #count = 0
  increment() {
    return #count++
  }
}

我想知道 - 我们可以开发一个打字稿插件或 tsconfig 选项来启用速记语法作为实验性功能吗?

我只是渴望光滑的人体工程学改进,以避免如此多的不必要的this.重复——正如提案所指出的,速记语法的缺点似乎不是我需要担心的重要问题,所以我当然很乐意在我自己的项目中设置"experimentalPrivateShorthand": true或类似的东西

可以这样做吗? 也许有充分的理由不可能? 所涉及的工作是什么? 干杯!

:wave: 追逐

@chase-moskal 除了超出 ECMAScript 标准的 Types 之外,TypeScript 没有实现任何东西。 这样做的原因是改变语义,正如私有字段和装饰器所证明的那样。

@chase-moskal 避免一直输入this的最实用方法就是在您的 IDE 中为其分配一个快捷方式(例如 F3)。 通过 fork TS 解析器或 Babel 解析器并编写插件,很多事情都是可能的,但它们都是大量工作,会使您与官方工具不同步。 我知道你的问题当然是关于官方支持的,只是想我会分享我的想法。

@jhpratt——打字稿曾经帮助我保持时尚。 它给了我过去的装饰器和箭头函数! 它曾经与 babel 具有竞争力,至少比现在更具竞争力

老实说,我真的很笨,我不能像一年多前使用 babel 的同行那样编写华丽的简约类,而且 babel 甚至拥有我渴望的所有花里胡哨的东西!


@mbrowne — 真正重要的并不是代码的“可写性”,而是“可读性” ,所以我们不用担心计算按键次数。 我的观点只是 javascript this重复往往是多余的、不值得的混乱

现在考虑一下可读性:当我们得到简写#private语法时,每次您看到this ,您都会立即知道它是为了访问公共成员——这是一个巨大的胜利可读性!


无论如何,我刚刚发现打字稿还不支持私有方法

所以这一切只需要更多的工作和时间,显然来自彭博社的人

没有私有方法来匹配字段,我们只需要等待(因为没有人会在同一个类中混合使用 typescript-privates 和 hashtag-privates 而不会发疯!)

那么,是bloomberg 团队在这里对打字稿进行现代化改造,一年前他们也参与了 babel 的相同隐私功能? 他们在做上帝的工作,我很好奇为什么! 保持! 干杯!

:wave: 追逐

是的,TypeScript 多年前就给了你装饰器。 你猜怎么着? 语义发生了变化,很重要。 现在,TypeScript 在不久的将来被困在支持遗留 API 中,并且无论何时决定删除它都会导致大量破坏。 箭头函数是 ECMAScript 规范的一部分,因此提出它完全无关紧要。

在达到第 3 阶段之前,TypeScript 目前没有实现任何 ECMAScript 提案。这就是您需要在 TS 感兴趣之前获得速记的地方。

是的,TypeScript 多年前就给了你装饰器。 你猜怎么着? 语义发生了变化,很重要。

我们生活在一个不理想的世界中,现在需要一些功能。 例如,装饰器提案仍处于第 2 阶段,但一些大项目(Angular)长期积极使用它们。 另一个例子:ECMAScript 没有为类成员指定protected修饰符,这对于解决实际问题很有用。

现在,TypeScript 在不久的将来被困在支持遗留 API 中,并且无论何时决定删除它都会导致大量破坏。

其他语言也在编译器标志下引入了实验性功能。

我不是说 TypeScript 应该在 Stage 1 或 Stage 2 下实现每个提案,但许多有趣的 TS 提案只是卡住了,因为 ECMAScript 中没有等效项,例如https://github.com/microsoft/TypeScript/issues/2000

@ikokostya我使用装饰器作为例子,说明在 TypeScript 实现它们之后语义发生了变化。 你真的是说这个速记是“现在需要的”吗? 相信我,我们可以管理额外的五个字符。 如果它对你很重要,你可以自由地 fork 编译器。

TypeScript 一直坚定地在第 3 阶段之前不实现任何东西,即使是在一个标志下。 这已经在之前的各种其他问题中进行了彻底的讨论。

除了绕圈子,我什么也没看到,所以除非出现值得注意的事情,否则我不会进一步回应。

@jhpratt我的观点与速记无关。 请通读我的评论。

关于 fork 的建议完全无关紧要。

不是每个人都同意——更重要的是,不是 TC39 委员会的每个人都同意——速记将使代码更具可读性或直观性。 有很多关于这个的讨论,由于这些问题,速记语法被转移到一个单独的提案中。 (我还没有考虑清楚,没有形成自己的明确意见,只是总结一下。)如果你想推动这个提议,继续的方法是向 TC39 提供反馈。 我确信在维护 TS 和实施所有已经达到第 3 阶段的提案方面已经有很多工作要做,所以很难想象这会被 TS 考虑,除非它在 ​​TC39 中进一步发展。

但我必须承认我真的很沮丧我们没有速记语法(见提案)

该速记将与管道提案不兼容,管道提案也可能使用#并且已经讨论成为第 2 阶段提案。 这么早实施提案然后进行重大更改确实没有意义。 在这么早的阶段,您甚至不知道哪个提案会获胜。

即使事实证明它是兼容的,我至少可以想到更多使用前缀#运算符的用例,它们比键入 5 个额外字符的速记更有用。

... 特别是当私有字段的大部分用例根本不在this时(例如, static isMe(obj) { try { obj.#x; return true; } catch { return false; } } ,举个例子)。

@phaux - 这是关于速记与管道的非常好的信息,谢谢!

@jhpratt

TypeScript 一直坚定地在第 3 阶段之前不实现任何东西,即使是在一个标志下。

足够公平,但必须指出,私有方法实际上是第 3 阶段,但还没有打字稿支持 - 看,我非常喜欢速记建议,但这只是美学 - 我实际上现在对缺乏私有方法和访问器感到更加沮丧

我假设(祈祷)bloomberg 团队正在继续上帝在打字稿上的工作,就像他们一年前为 babel 所做的那样? 如果是这样,那么我们真的只需要耐心等待:)

在我看来,在 ecmascript 功能方面,打字稿过去与 babel 和浏览器相比更具竞争力,而现在它实际上太保守了——我们处于一种情况,一年前 babel和 chrome都发布了私有字段(未标记)布隆伯格来拯救我们

我对打字稿和 babel 功能集之间的逐渐分歧感到不安——去年我的 babel 朋友一直在编写精美流畅的代码,而我仍然在这里支付打字稿罚款——他们在嘲笑我!

我喜欢曾经提供实验性标志的打字稿,它使我能够决定我愿意在未来冒险重构什么来为我购买一些很棒的功能——现在打字稿的立场是不是让开发人员决定这些风险太危险了,以及那个打字稿现在是我的保姆?

越来越多,看起来我可以选择很棒的功能或静态类型——但我现在不能两全其美,所以我内心的认知失调越来越严重

我真的很好奇这里的动态——如果布隆伯格没有像一个穿着闪亮盔甲的骑士那样介入,打字稿自己接受挑战需要多长时间? 或者这是一个打字稿实验:“如果我们只是避免这些新功能......社区会在多久之前......为我们做这件事?”,哈,即使我想知道这也是一个非常愤世嫉俗的人! 或者,这是一个非常酷的善意合作,探索为开源提供资金和支持的新途径,只是比预期慢了一点? 或者也许 typescript 的哲学比以前更加保守? 我们在这个频谱上的什么位置?

为了实现第 3 阶段的功能,打字稿是否缺乏带宽或优先级?

抱歉,在此大吼大叫,嘿,我真的不是想在这里粗鲁或严肃地指责,只是从我局外人的角度抛出一些想法。 我只是一个用户,我真的很好奇这里的更多知情人士会对我画的这些图片做出什么反应——有趣的讨论,我很感激你们!

:wave: 追逐

我喜欢曾经提供实验性标志的打字稿,它使我能够决定我愿意在未来冒险重构什么来为我购买一些很棒的功能——现在打字稿的立场是不是让开发人员决定这些风险太危险了,以及那个打字稿现在是我的保姆?

这不是要照顾你。 这是关于不想花时间实现功能,当提案中的语义发生变化时,这些功能将不可避免地成为维护负担。 当它们与 TS 的实现发生冲突时,他们绝对不想花时间弄清楚如何协调已更改的语义。 他们有更好的事情要做。 仍然有大量与类型相关的问题需要解决,因此将他们有限的资源用于解决这些问题是有意义的,而不是尝试在解决类型系统问题之上完成 TC39 的工作。

至于私有方法和访问器:它们也没有在 V8 中实现。 类方法和实例字段是不同的,它们不能只是……翻转开关来支持它们。 实施它们需要实际时间,而且他们已经忙于工作,而且他们是一个小团队。 此外,规则不仅仅是提案需要处于第 3 阶段:他们还明确表示,他们希望对提案的语义有很高的信心才能成为最终版本。 虽然很少见,但语义 _can_ 在第 3 阶段发生了变化。该功能没有在 V8 中实现,没有充分的理由。 不过不要误会我的意思; 我也很想看到该提案得到实施,并迫不及待地想使用它。 但是,从早期阶段实施提案是浪费时间,TS 团队的时间最好花在其他地方。 有无数的第 2、第 1 和第 0 阶段提案我会_喜欢__今天_使用,但我明白为什么我还不能拥有它们。 耐心点我的朋友。

如果您更喜欢 babel 为您提供的选项,您也可以专门使用 babel 来转换您的打字稿。

@0kku——所以你是说这只是一个带宽/容量问题,而不是一个哲学问题——积压的错误现在比第 3 阶段功能的实现具有更高的优先级,但是在 typescript 的早期历史中,也许它的错误更少,所以更容易为实验性实现分配容量? 我可以购买这个理论,我们的反应应该是等待或贡献

@ljharb——哦,现在这很有趣——是否真的可以以这种方式一起运行 typescript 和 babel? 实现两全其美?

但我只是看不出 vscode ts 语言服务如何在不破坏不熟悉的语法(例如私有方法)的情况下仍然可以工作? 缺乏智能感知会严重影响 typescript 的价值主张——如果必须完全禁用智能感知,那么该策略就行不通了

从长远来看,如何解决这个问题? 我想如果我们为每个实验性功能的语法区分特定的打字稿错误,而且,如果打字稿项目可以在 tsconfig 级别禁用这些特定错误 - 那么我们将有机会打开大门以利用 babel 功能和打字稿功能同时——这个人真的很酷,能解决整个班级的抱怨……干杯!

:wave: 追逐

@ljharb

您也可以专门使用 babel 来转译您的打字稿

我想您可以设置一个类型检查过程,在该过程中您只使用 Babel 转译私有方法(但保留其他所有类型的类型)并使用tsc对该代码进行类型检查。 (构建脚本,在类型检查通过后,只会单独使用 Babel。)但是你必须忽略 IDE 中的许多语法错误 - 我认为这对大多数人来说是一个交易破坏者。

@chase-moskal 尽管@0kku所说的总体上是正确的,但我目前没有看到任何不在 TS 中实现私有方法的理由。 我认为更多的是该提案比 class 字段更晚到达第 3 阶段,并且实现者仍在努力。

如果您想知道为什么我们不热衷于尝试使用实验性功能,请参阅--useDefineForClassFields巨大复杂性 clusterfoxtrot 。 我们很早就实现了类属性初始化器,假设不可能存在具有不同语义的可能的 TC39 提案,但我们大错特错。

装饰器趋向于在同一条船上,如果您认为我们可以完全放弃对旧语义的支持,您会感到惊讶。 多家大公司围绕它构建了大型的被广泛采用的框架; 我们可以说“好吧,标志名称以experimental开头,所以您应该知道过去 5 年支持的此功能可能会在某一天出现并消失”,这是完全不现实的。

对于这两个功能,我们将在余生中坚持在这里维护两个微妙不同的代码路径,这很糟糕,但这是权衡——我们非常致力于保持构建到构建的 TypeScript可以在不破坏代码运行时行为的情况下进行更新; 当它对您有利时(例如,您的程序继续工作),这种权衡是不可见的,但您可以更容易地看到急切功能采用方面的缺点。

从我们的角度来看,您不能免除版本到版本的运行时兼容性,就像您不能免除疏忽责任一样。

尽管社区遭到了大规模的抵制,我们也推迟了对可选链的早期采用——如果每次有人说“好吧,把它放在旗子后面”我都有五分钱,我会在船上打字。 但这是正确的做法,因为我们不得不猜测(null)?.prop产生了什么,我们绝对会猜测null (不是undefined ),我们' d 承受着另一个持续的复杂性负担来解决这个问题。 这里有一个强大的反事实优势,因为没有人会被困在 300 万行代码库中,代码库中充满了?.用法,他们有时依赖于产生null用法,而没有办法甚至弄清楚如何过渡到不同的undefined行为。

Bloomberg 实施私有字段是因为他们对拥有该功能感到非常兴奋,并渴望为 TypeScript 做出贡献。 如果他们没有遇到这种情况,我们就会自己实现这个功能,就像其他一切一样。

总的来说,我会说 JavaScript 的时间线非常非常长,实际上,您可以在 2020 年编写符合人体工程学的优秀 JavaScript,而无需使用 2024 年的语法,就像您可以在 2016 年不使用 2020 年的语法编写良好且符合人体工程学的 JS 一样。 没有人会因为无法使用甚至还没有最终确定语义的语法而受阻; 那时它只是想象中的编程。

不仅如此,甚至不能 100% 确定当前的类字段提案及其所有细节将以当前形式进入第 4 阶段(特别是现在有一家 TC39 成员公司鼓动完全取消提案并取而代之)与一个不同的)。 我猜有 95% 的把握,但总的来说,即使实施第 3 阶段的提案也并非完全没有风险。 但是,第三阶段之后进一步变化的可能性非常低,所以我认为目前的TS政策是一个很好的政策。

现在有一家 TC39 成员公司鼓动完全废弃 [class fields] 提案并用不同的提案取而代之

有趣,介意点一个链接吗?


这是一个想法:也许 TS 团队可以花一些时间来改进插件系统,为插件作者提供一个清晰的 API,该 API 可以连接到编译时和语言服务器协议智能感知时间。 这将使第 3 方有可能实现他们想要的任何实验性功能,包括新语法,并且仍然可以在 IDE 和文本编辑器中使用智能感知。

最后我检查过, ttypescript是在tsconfig.jsonttypescript并需要依赖终端输出而放弃我们良好的 VS Code 体验,而 VS Code 无法理解语法并抛出错误。

然后 TypeScript 可以专注于稳定的功能,让 3rd 方制作或使用有风险的实验性功能(就像在 Babel 生态系统中一样简单)。

有趣,介意点一个链接吗?

https://github.com/microsoft/TypeScript/pull/30829#issuecomment -541338266

您可以使用 Babel 插件执行的语法操作非常有限; 基本上解析器必须已经支持它。 例如, do表达式“插件”仍然需要 Babel 本身的核心逻辑: https :

私有类方法和访问器是否存在可以遵循的问题?

@瑞安卡瓦诺

对于这两个功能,我们将在我们的余生中坚持在这里维护两个微妙不同的代码路径

我不认为它应该这样发展,我可以想象它会伤害整个社区。 如果装饰器达到第 3 阶段,我认为提供一些时间升级到新版本的装饰器是合理的。 可能会暂时支持两者,可能会在 TypeScript 4+ 中进行硬切换并删除遗留装饰器。 我不知道新旧装饰器之间的区别,因为我不使用它们(好吧,实验性功能)。 但我认为,如果提案不能满足他们的需求,受影响的项目应该按照提案工作。 这对每个人都更好。 TypeScript 是挑起关于遗留和实验性功能的战争的错误场所。

我很遗憾来到这里:/

@瑞安卡瓦诺

您可以使用 Babel 插件执行的语法操作非常有限; 基本上解析器必须已经支持它。

真的。 但是为了与 TypeScript 进行比较,在 Babel 中,您可以只 fork 解析器并设置您的babel.config.js以使用自定义解析器和您创建的任何自定义语法插件。 是的,这是很多工作(尤其是第一次学习如何添加新语法),但我不知道 TS 有任何等效选项,当然在 Babel 中,基于现有语法编写转换插件要容易得多。 我不确定 TypeScript 中自定义选项的当前状态是什么,但是当我几年前最后一次查看它时,看起来除了分叉整个事情之外没有其他选项可以扩展它。

试试这个: https :

私人海事组织的哈希是丑陋和混乱的。 这很难执行,因为没有办法以其他方式实施它们。 没有像 TS 中那样的构建步骤。 结果是它只是用符号堵塞了代码,以获得“硬私有”的很少收益,人们认为这是编写 JS 的“正确”方式,因为许多人被教导默认情况下事物应该是私有的。
在将其推入标准之前应该有更多的提案,尤其是在对此事存在明显分歧的情况下。

@robot56默认情况下应该是私有的。 他们被教导所有的东西都应该通过反射来访问,事实上,这对任何人来说都不是一件好事。

@ljharb是的,他们应该这样做。 然而,当声明私有的方式变成在变量前面扔哈希符号时,在 JS 中创建类的“正确”方法意味着教人们只在成员变量前面放置哈希。 不仅在声明它们时,而且在引用它们时也是如此。 如果您来自其他语言,则尤其令人困惑。 在类中看到类似this.#x = this.#something();和声明的内容时,我的第一个想法是散列是变量本身的一部分。 我永远不会猜到它是一个修饰符。 公共的下划线,这似乎也倒退了。 这与 TS 并不真正相关,但我猜这只是一个烦人的咆哮。

是的,在熟悉的情况下学习新事物可能是一种调整。 我相信 JS 社区会继续学习!

(散列变量本身的一部分, this.#x名称不是“x,而是私有”,但实际上, #x是该词法范围内的唯一值)

是的,在熟悉的情况下学习新事物可能是一种调整。 我相信 JS 社区会继续学习!

你说的方式,听起来好像是在学习一些可以增加我们编程智慧的东西,而这只是另一个必须记住的 JS 怪癖:D

此页面是否有帮助?
0 / 5 - 0 等级

相关问题

CyrusNajmabadi picture CyrusNajmabadi  ·  3评论

Antony-Jones picture Antony-Jones  ·  3评论

siddjain picture siddjain  ·  3评论

manekinekko picture manekinekko  ·  3评论

bgrieder picture bgrieder  ·  3评论