🔍搜索词
isolatedDeclarations transpileModule computed property name
✅可行性检查清单
- 这不会对现有的TypeScript/JavaScript代码造成破坏性的更改
- 这不会改变现有JavaScript代码的运行时行为
- 这可以实现,而无需根据表达式的类型发出不同的JS
- 这不是一个运行时特性(例如库功能、JavaScript输出的非ECMAScript语法、JS的新语法糖等)
- 这不是一个请求添加新的实用类型: https://github.com/microsoft/TypeScript/wiki/No-New-Utility-Types
- 这个特性将与我们设计目标的其他部分一致: https://github.com/Microsoft/TypeScript/wiki/TypeScript-Design-Goals
⭐建议
背景
目前,在isolatedDeclarations
下的计算属性名称非常有限。今天,你可以写{[Symbol.iterator]: ...}
,仅此而已。这个限制之所以存在,是因为对于任意的{[expression]: ...}
,我们不知道该类型应该是{[expression]: something}
、{[expression: string]: something}
甚至是{}
(或者是未来的{f1: something} | {f2: something}
)。如今,类型中的计算属性名称必须完全是单个可延迟绑定的名称——不多也不少——与此同时,对象表达式(以及类声明)中的计算属性名称则更加灵活,允许我们使用更多内容。
到目前为止,这对TS用户来说效果很好,因为我们基本上预先解决并缓存了表达式计算名称解析为我们的声明文件的内容。不幸的是,对于isolatedDeclarations
用户来说,这会带来问题,因为计算属性名称中的expression
可能来自或依赖于另一个文件的类型信息。在这种情况下,我们无法知道如何发出表达式的类型。你可能会乐观地发出{[expression]: something}
,但如果expression
最终在全程序上下文中评估为string
或any
,那么声明文件将产生错误并提供不正确的类型信息。
建议
在这种情况下,我们可以使用一种语义上的opt-in来确保在计算表达式的类型中保留计算属性名称。一种形式的计算属性名称意味着,当你看到它时,它总是确保计算属性名称出现在输出中,并且如果在检查时无法生成有效的计算属性名称的声明文件,就会发出检查器错误。
我建议我们重用一些现有的语法,并为其赋予新的意义来实现这一点——一个 satisfies keyof
后缀Assert,仅在计算属性名称位置有效,并且仅适用于点实体名称表达式。这意味着你可以写
export const a = {
[something satisfies keyof]: () => {}
}
然后我们总是会发出
export const a: {
[something]: () => void;
};
并且如果 something satisfies keyof
不是一个确切的单一唯一符号、字符串字面量或数字字面量类型(这是在类型位置计算属性名称中有效的),就会发出错误。
兼容性
只有 isolatedDeclarations
相关的作者真正需要考虑这个特性——它会被从声明文件中擦除,因为它们已经检查了这个约束,所以库消费者永远不会看到它。不使用 isolatedDeclarations
的人永远不会被迫使用它,因为他们总是可以在没有Assert的情况下生成声明类型。这很容易集成到 isolatedDeclarations
快速修复程序中。这与现有的 satisfies keyof T
Assert不冲突,因为它们需要一个类型参数作为 keyof
的输入。将来还有可能允许在其他位置和对任意表达式种类上检查相同的不变式——即表达式必须完全是一个字面键类型——如果我们认为这样的检查在比计算属性名称更广泛的上下文中有用途的话。
附录:使错误情况更好
一旦有了 {[expression satsifies keyof]: ...}
的支持,我们就知道计算属性名称应该始终产生恰好一个对象键,即使 expression
不会产生有效的键类型(因此会产生错误)。在这种情况下,可以通过覆盖 expression
的类型为特定于 expression
符号的属性键来提高其价值,然后在后续的 obj[expression]
查找失败时回退到使用该符号。这样一来,我们就可以尽可能地保留用户的意图,而不必迅速回归到未经检查的状态。这个方法很酷(我已经有一个可行的原型),特别是在我们的语言服务在后台加载整个程序时执行单文件检查模式的情况下,但实际上并不一定需要这个特性。我对这个问题的开放问题只是
- 支持这种场景是否值得用一个特殊情况来支持?
- 如果包含其中一个回退属性键的结果类型的值是
keyof
呢?应该调整string | number | symbol
结果吗?回退错误属性应该完全从keyof
中过滤掉吗?
5条答案
按热度按时间svgewumm1#
...并在满足 keyof 条件的情况下对某些内容发出错误,如果某些内容不完全是单一的唯一符号、字符串字面量或数字字面量类型(这是在计算属性名时有效的类型位置)。
我想不明白的是,如果你已经能够对
something
位置中的任意表达式进行这种检查,那么额外的语法为你带来了什么好处?那时感觉就像是噪音。kse8i1jr2#
我不明白的是,如果你已经能够对任意表达式进行检查,那么额外的语法能给你带来什么好处呢?这感觉就像是噪音。
给定
,
没有错误,而
在
something
上报错:A satisfies keyof computed property name must be exactly a single string, number, or unique symbol literal type
。并且
根据解析出的
something
的类型发出,但是
总是发出,即使
something
无法解析:hujrc8aj3#
这基本上是一种将声明文件中计算属性名称保留到输入文件中的错误提取方法。
pqwbnv8z4#
啊,所以它基本上是一个语法提示,不要将其扩展为索引签名,我们总是希望它在类型中显示为计算属性。
satisfies keyof
中的提示感觉非常尴尬和不直观,但这完全是在🚲 🏠的领域,可能还太早了。r6hnlfcb5#
既然
Symbol.iterator
在这里被提到了,我想把Symbol.asyncIterator
也放进讨论中,因为我在其他地方没有看到它的身影,而且目前还会产生错误。