[英]Does Typescript (really) follows the naming convention for parameterized types (T, U, V, W) in Generics?
我不确定在 TS 中我们是否遵循 C++/Java 或许多其他语言( T,U,V,W
)等参数化类型的命名约定。
我多次看到 TS 中参数化类型约定的混合使用。 例如,在TS 2.8 的发行说明中:
type ReturnType<T> = T extends (...args: any[]) => infer R ? R : any;
为什么R
而不是U
?
然后,在下一个示例中:
type Unpacked<T> = T extends (infer U)[]
? U
: T extends (...args: any[]) => infer U
? U
: T extends Promise<infer U>
? U
: T;
为什么是U
而不是R
?
另一个示例,在上面代码的同一代码块中:
type T0 = Unpacked<string>; // string
type T1 = Unpacked<string[]>; // string
type T2 = Unpacked<() => string>; // string
type T3 = Unpacked<Promise<string>>; // string
type T4 = Unpacked<Promise<string>[]>; // Promise<string>
type T5 = Unpacked<Unpacked<Promise<string>[]>>; // string
但是在TS源代码中:
// We represent tuple types as type references to synthesized generic interface types created by
// this function. The types are of the form:
//
// interface Tuple<T0, T1, T2, ...> extends Array<T0 | T1 | T2 | ...> { 0: T0, 1: T1, 2: T2, ... }
上面的问题只是说明问题的例子,你不需要回答它们。 我可以添加一些其他示例,其中U
有时被视为返回类型,有时只是第二种类型。
我真正的问题是:我们(真的)是否遵循 TS Generics 的Java 通用类型约定? 如果不是,TS 对 Generics 遵循什么样的约定? TS 中共存了多少种不同的类型约定(除了类型名称的明显 PascalCase 和类型属性/方法的 camelCase)?
(主要来自评论)
我能想到的最接近的回答这个不仅仅是我的观点,是指向一些描述“TypeScript 类型参数命名约定”是什么的文档,并将其与您链接的Java Generics 教程文档进行比较。
如果是这样,TypeScript设计团队对此的官方立场似乎是“我们不打算将任何此类约定强加给其他人”,或者“TS中没有规范的命名约定”。 请参阅microsoft/TypeScript#6168和microsoft/TypeScript#878 ,特别是此评论:
[我]一般来说,我们对为人们决定风格的东西不感兴趣。 说 TS 有一种被批准的样式违背了我们的理念,即我们在这里为 JS 提供类型,无论您如何编写它(当然,在合理的参数范围内)。
还有ESLint 的naming-convention
规则和TSLint 的naming-convention
规则,这使得在经过 linter 检查的代码库中强制执行类型参数命名约定成为可能,但默认情况下似乎没有这样做。 因此,似乎没有任何约定足够正式,可以默认强制执行。
为了比较起见,让我们看一下您链接的 Java Generics 教程文档中的相关部分:
类型参数命名约定
按照惯例,类型参数名称是单个大写字母。 这与您已经知道的变量命名约定形成鲜明对比,并且有充分的理由:如果没有这个约定,就很难区分类型变量和普通 class 或接口名称之间的区别。
最常用的类型参数名称是:
- E - 元素(被 Java Collections 框架广泛使用)
- K - 键
- N - 数字
- T - 类型
- V - 价值
- S、U、V 等 - 第 2、第 3、第 4 类型
您将在本课的 Java SE API 和 rest 中看到这些名称。
请注意,上面列举的列表被描述为“最常用的类型参数名称”,而不是“唯一允许的类型参数名称”; 它是一个示例列表,因此是描述性的而不是规定性的。
关于选择“单个,大写字母”的部分更接近于处方:大写字母倾向于区分类型名和变量名,单字符类型名倾向于区分类型参数和特定类型,如 class 或接口。 但我有同样的感觉,这与其说是来自上层的法令,不如说是对普遍做法的观察。
所以我们大概可以停在那里说“在 TypeScript 或 Java 中没有官方或规范的类型参数命名约定,任何非官方的此类约定都是见仁见智的问题。”
但为了试图列出我认为TypeScript 中的非官方约定实际上是什么,我将打开 go。 请记住,这是我的意见,人们可能会不同意。
我想说的是上面列出的 Java 命名约定与我认为 TypeScript 泛型类型参数的实际命名约定非常接近:使用单个大写字符,或者对应于它们所代表的第一个字母,例如作为:
T
代表“类型”,最通用也是最常用的类型参数名称;K
表示“key”,或P
表示“property”,两者都倾向于受PropertyKey
或keyof T
或keyof SomeInterface
或keyof SomeClass
的约束;V
表示“值”,最常与K
表示“键”成对使用;A
for "arguments" and R
for "return", corresponding to the rest parameter list and return type of function signatures respectively, like (...args: A) => R
;N
表示“数字”, S
表示“字符串”, B
表示“布尔值”,用于受基元约束的类型参数;或一些相关类型的序列,例如:
T
, U
, V
, W
等,从T
开始表示“类型”,然后在需要更多类型时遍历字母表,请记住,您只能通过这种方式获得一些;A
, B
, C
, D
等,从字母表的开头开始,当您希望使用一大堆类型参数并且您还没有将类型参数用于其他用途时。这样的约定不是绝对的,并且在必要时倾向于弯曲以避免歧义或其他混淆。 如果您需要比上面没有名称冲突的类型参数更多的类型参数,则可能需要在名称中添加一个字符:
T0
, T1
, T2
, T3
等,附加数字得到相关类型的序列;KT
、 KU
、 KV
:分别为T
、 U
和V
的“键”添加前缀K
;它与我认为的传统方式相去甚远,但仍然很常见,可以编写简短的 UpperCamelCase 名称以更好地描述类型所代表的内容,缺点是它们可能会开始混淆特定类型而不是类型参数:
Key
, Val
, Prop
, Arg
, Ret
, Type
, This
以下是非常规的(请记住,我的意见在这里:)并且应该避免,除非有一些压倒性的情有可原的理由这样做:
InputType
或Properties
;TNotRecommended
等较长类型名称上添加大写T
前缀;t
或u
或myType
;
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.