reactjs, typescript 中定义 action type 时,经常看到一种使用方法, type & const 用同一个名字,不知其深意?

2020-05-11 08:50:21 +08:00
 yazoox
export type INSTALL_PLUGIN_DIALOG = "Feature.INSTALL_PLUGIN_DIALOG";
export const INSTALL_PLUGIN_DIALOG: INSTALL_PLUGIN_DIALOG = "Feature.INSTALL_PLUGIN_DIALOG";

如上所示。先定义了一个 type INSTALL_PLUGIN_DIALOG,其值可能是就是它自己“INSTALL_PLUGIN_DIALOG”, 或者一种变形“Feature.INSTALL_PLUGIN_DIALOG"。

然后,又定义了一个 const,名字和类型一模一样,然后这个 const 的值和上面类型定义的那个值也是一模一样。

关键是这个 type 和 const 还都 export 了。那么, 在其它文件里面 import {INSTALL_PLUGIN_DIALOG} from "<file_name>",到底引入的是 type 还是 const 呢?

这...... 这么折腾,目的是何?或者换个说法,优点是什么?

2547 次点击
所在节点    程序员
18 条回复
Jeremial
2020-05-11 09:03:57 +08:00
我理解是用的时候, 如果在冒号后面是当做类型来用, 其他情况当做值来用.
Hypn0s
2020-05-11 09:17:52 +08:00
类型是可传递的,不然经过函数倒一手就是普通的 string 了
wszgrcy
2020-05-11 09:36:31 +08:00
jquery 函数和 jquery 对象,应该好理解吧?
mxT52CRuqR6o5
2020-05-11 09:48:49 +08:00
为了显式告诉 typescript 类型系统这个变量是个内容特定的字符串,而不是单纯的 string 。
有其他写法可以更简单的达到目的
namelosw
2020-05-11 09:49:04 +08:00
一个是类型(type),一个是值(term)。有的地方比如泛型或者签名需要 type 的时候就传 type,需要值的时候传的是 const 。TypeScript 自己能按上下文理解,所以同名的时候它自己就考眼力见判断了。

比如 type Action = INSTALL_PLUGIN_DIALOG | OTHER_ACTION,这时候用的就是 type 。
比如 if (action.type === INSTALL_PLUGIN_DIALOG),这时候用的就是 term 。
少了一个这两个就会红一半。

理论上本来其实写一个 const INSTALL_PLUGIN_DIALOG 就行,但是 TypeScript 为了让大部分人不会觉得特别奇怪,所以把这个类型推断泛化了,导致这个 case 写起来反而麻烦。
你可以想象平行宇宙有个另外的 TypeScript 版本可以这样写:
const INSTALL_PLUGIN_DIALOG = "Feature.INSTALL_PLUGIN_DIALOG"
type Action = typeof INSTALL_PLUGIN_DIALOG | typeof OTHER_ACTION

但是实际上这样写不行,因为 typeof INSTALL_PLUGIN_DIALOG 返回的类型是 string 而不是"Feature.INSTALL_PLUGIN_DIALOG"

从具体到宽泛的角度来看,"Feature.INSTALL_PLUGIN_DIALOG"是一个 string,而 string 是一个 Object 。用极端的角度看,不然 typeof INSTALL_PLUGIN_DIALOG 应该是"Feature.INSTALL_PLUGIN_DIALOG",不然应该是 Object 。但是实践上还是推断成 string 比较好用,特别是作为函数返回值的话,如果像上面假设的推断成具体字符串,那几乎每个返回字符串字面量的函数都要手写签名才行。

所以因为我们没有用平行宇宙的版本,就只能写两遍了。
vanishcode
2020-05-11 09:50:50 +08:00
momocraft
2020-05-11 09:59:18 +08:00
可能没特别目的, 只是配合设计

TS 设计 value 和 type 是不同 namespace.

另一个例子: export class A 的时候其实也同时 export 了 value (constructor) 和 type (instance)
SilentDepth
2020-05-11 10:19:57 +08:00
TypeScript 有两个标识符空间,一个是普通 ES 的,一个是 TS 类型的。两个空间(通常)互不影响,也无法直接交互。于是当你想把 "Feature.INSTALL_PLUGIN_DIALOG" 这个字符串值单独作为类型(而不是视为普通的字符串)时就需要那么写了。
bnm965321
2020-05-11 10:43:57 +08:00
楼上有几位没有看懂,楼主说的是 类型名 /变量名 是一样的。

这种用法真的见过比较少,很多代码的 type 是用匈牙利命名法
yazoox
2020-05-11 11:32:49 +08:00
@bnm965321 兄弟,能多分享一些么?
可能我们这边的已有项目,就是这么命名的。不知道你们有没有其它的命名方法,或许更容易阅读和理解一些。

thx.
yazoox
2020-05-11 11:33:50 +08:00
@mxT52CRuqR6o5 兄弟,能多分享一点,你提到的“有其他写法可以更简单的达到目的”么?
thx
bnm965321
2020-05-11 11:42:01 +08:00
@yazoox 可以参考微软 FluentUI 的代码,他们是用匈牙利命名法,第一个大写的字母代表类型的种类。一般 action type 就是 AActionName

https://developer.microsoft.com/en-us/fluentui#/controls/web/button
mxT52CRuqR6o5
2020-05-11 11:42:34 +08:00
```
export const INSTALL_PLUGIN_DIALOG = "Feature.INSTALL_PLUGIN_DIALOG" as const;
```
mxT52CRuqR6o5
2020-05-11 12:48:14 +08:00
@yazoox
export const INSTALL_PLUGIN_DIALOG = "Feature.INSTALL_PLUGIN_DIALOG" as const;
export type INSTALL_PLUGIN_DIALOG = typeof INSTALL_PLUGIN_DIALOG;

前面那个回复少了一句,少下面那句对外使用语义有些区别
Austaras
2020-05-11 14:23:45 +08:00
这个是古代的做法, 当代直接 as const 就 i 完了
azh7138m
2020-05-11 15:33:28 +08:00
楼上分析的挺好。。。
可是 as const 出来大半年了。。。
Exin
2020-05-11 16:46:01 +08:00
这做法一点也不少见,如果 OOP 的话,每个 class 都既是 type 也是 term 。
weixiangzhe
2020-05-11 22:19:56 +08:00
typescript 里有 const xxx = xxx as const 加一

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/670403

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX