[Day13] TS:什麽!这个 typeof 和我想的不一样?

typeof operator

这是我们今天要聊的内容(不是业配),老样的,如果你已经可以轻松看懂,欢迎直接左转去看我同事 Ken 精彩的文章 — 「From State Machine to XState」。

Typeof Operator in JavaScript

多数 JavaScript 的开发者都知道,在 JS 中有 typeof operator 可以使用,使用上虽然有一些要留意的细节,但基本上 typeof 可以帮开发者判断某个变数的型别:

// https://javascript.info/types#type-typeof

typeof undefined; // "undefined"
typeof 0; // "number"
typeof true; // "boolean"
typeof 'foo'; // "string"
typeof (() => {}); // "function"
typeof null; // "object"

Typeof Type Operator in TypeScript

但今天我们要聊的是 TS 中的 Typeof Type Operator,多一个 type 差很多。

这个 typeof 的用法其实非常简单,我们知道在 TypeScript 中,即使没有针对变数定义型别(Type Annotation),它还是会自动帮我们推导出该变数对应的型别,只要把滑鼠移到该变数上方,就可以看到 TS 自动帮变数推导出其可能的型别:

Type Inference

这里 TypeScript 会自动把 conference 这个「变数」推导为如下的「型别」:

const conference: {
  name: string;
  year: number;
  isAddToCalendar: boolean;
  website: string;
};

但这个被自动推导出来的型别需要滑鼠移上去时才看得到,有没有什麽方式能够把这个「自动推导的结果」建立成一个可以被使用的型别呢?

有,就是 Typeof Type Operator,它的语法一样就是 typeof ,後面可以接「变数」或「属性」:

type Conference = typeof conference;

这个建立出来的型别 Conference 就会是刚刚一开始滑鼠移到变数 conference 上时显示的结果:

Typeof Type Operator

那回到今天最开始的例子:

const conference = {
  name: 'MOPCON',
  year: 2021,
  isAddToCalendar: true,
  website: 'https://mopcon.org/2021/',
};

type ConferenceKeys = keyof typeof conference;

搭配在第 4 天时对 keyof 的了解,读者应该可以想到 ConferenceKeys 的结果会是什麽。因为 typeof conference 是物件型别,所以 keyof typeof conference 就会是把所有该物件型别所有的 key 取出组成 Union Type:

Typeof Type Operator

读者也许会好奇,不能直接用 keyof conference 就好,一定要在 conference 前面加上 typeof 吗?学习 TS 的重点之一就是拿掉看看会发生什麽事,现在就让我们拿掉原本的 typeof 看看:

Typeof Type Operator

这时候 TypeScript 报错了,错误内容是:

'conference' refers to a value, but is being used as a type here. Did you mean 'typeof conference'?

意思是,conference 是 value,但它却被当成 type 来使用。为什麽会有这个错误呢?

还记得 conference 本身是一个 JavaScript 中的变数而不是 TypeScript 中的型别吗?因为 keyof 後面只能接的是「型别(Type)」,不能接 JavaScript 的「值(value)」,因此,一定会需要透过 typeof 先把 JS 的变数值转成 TS 的型别後,才能使用 keyof 这个 operator。

区分 JavaScript 和 TypeScript 的 typeof

其实...也没什麽好区分的。

虽然这两个的语法都是 typeof,但执行的时间点是完全不同的,JavaScript 的 typeof operator 会在程序执行时(runtime)呼叫,而 TypeScript 的 typeof type operator 则只有在 TypeScript 中「操作型别」时会用到,一旦把 .ts 编译成 .js 後,到了 runtime 会无影无踪(毕竟 JS 原生并没有这种强型别的概念)。

可以分辨的出那个是 JavaScript 的 Typeof Operator,那个是 TypeScript 的 Typeof Type Operator 吗?

const conference = {
  name: 'MOPCON',
  year: 2021,
  isAddToCalendar: true,
  website: 'https://mopcon.org/2021/',
};

type Conference = typeof conference;
const typeofConference = typeof conference;

补充:把 enum 的所有 key 取出成 union types

还记得在 Day11 中曾提到,透过 Template Literal Types 可以把 enum 的 values 取出变成联集吗?

enum MANUFACTURE {
  APPLE = 'apple',
  SAMSUNG = 'samsung',
  GOOGLE = 'google',
  SONY = 'sony',
}

type Manufacture = `${MANUFACTURE}`; // "apple" | "samsung" | "google" | "sony"

现在如果是想要把 enum 的 key 取出变成 union types 的话,则可以使用到今天提的 Typeof Type Operator:

// Get all keys of enum
type ManufactureKeys = keyof typeof MANUFACTURE; // "APPLE" | "SAMSUNG" | "GOOGLE" | "SONY"

是不是很酷又很方便啊!现在读者就可以根据需要取得 enum 的 keys union 或 values union 了。

范例程序码

https://tsplay.dev/mAV3RW @ TypeScript Playground

工商时间

笔者今年将会在 MOPCON 2021 分享主题「用 Type 建立 Type:一起来当个 TypeScript 的型别魔术师」,提供给对 TypeScript 有兴趣,又觉得每天追文章实在太辛苦的你来参考看看!但即使报名了 MOPCON 还是可以继续追踪铁人赛啦!

MOPCON2021

参考资料


<<:  DAY28 - [React] useContext 概念篇

>>:  连续 30 天 玩玩看 ProtoPie - Day 13

【18】GlobalAveragePooling 与 Flatten 的差异与比较

Colab连结 今天要探讨的主题在模型从CNN Layer 转变成 Dense Layer 时,使用...

【D13】发现新book:Account Data- Position

前言 看了一些交易资料,现在来看看一些帐务相关的资料吧。 参考网站:Position 本日程序码使用...

不是使用专用的、标准化的设备清理命令的清除方法:消磁(Degaussing)

清理方法(The sanitization method),清除(purge),将使数据恢复不可行,...

Stream Processing (2) - Chande Data Capture

保持同步 资料工程师修炼之路走到现在,真的没有一个系统能同足满足资料储存、查询和逻辑处理,现实世界的...

[Angular] Day28. Control Value Accessor (CVA)

前几篇介绍了 Form 的基本操作与概念,也介绍了如何在表单中加入验证,最後要来介绍 Angular...