上面这个是今天会提到的内容,如果你已经可以轻松看懂,欢迎直接左转去看我同事 Andy 「前端工程师学习 DevOps 之路」的精彩文章!。
昨天我们整合了过去所学的知识写了一个函式,後面我们会提到更多 TypeScript 中用来建立 Utility Types 所需的知识,但今天让我们继续熟悉前几天学到的内容,并试着建立一些常用的 Utility Types 吧!
前几天学到的:
extends
限制泛型keyof
的使用一般写程序时,或多或少会写过一些 utility function,它们就像小工具,可以接受 input 然後做了某些处理後回传 output,举例来说,以阿拉伯数字作为 input,接着以中文的数字作为 output;或者以字串作为 input,根据某些字元拆成阵列後作为 output。不管功能是什麽,这种「小工具」类,有 input 和 output 的函式,就可以称作 utility。
除了函式之外,在 TypeScript 中,也有不少处理型别的小工具可以使用,和前面提到的 utility functions 最大的不同在於,代入 Utility Types 的 input 会是 TypeScript 的「型别」,而不是一般的 JavaScript value,也就是说,Utility Types 会以「型别」作为 input,并且以另一个「型别」作为 output,也就是说,Utility Types 就像函式一样可以带入 input 得到 output,透过 Utility Types 将可以「根据一个型别,来建立出另一个型别」。
Utility Types 有时也称作 Type Function,TypeScript 本身就有许多内建的 Utility Types,像是 Partial
、Required
、Record
、...等等。这里我们先来看一下比较基本的,先对 Utility Types 有一点感觉,等後面学到更多知识後,再来看其他更进阶的。
今天这里所提到的一些 Utility Types 读者们可能会觉得有点鸡肋,似乎不需要建立 Utility Types 就可以达到一样的功能,不过相信我,等到後面掌握更多 TypeScript 的知识後,读者将会有一种看到不同世界的感觉。
先来看一下官方提到的 OrNull
这个 Utility Types,它的写法是这样:
// Utility Type
type OrNull<Type> = Type | null;
看起来非常单纯,使用上可以像这样:
type Manufacture = 'Apple' | 'Google' | 'Samsung' | 'Sony';
// 使用 OrNull 这个 Utility Type 产生新的型别 ManufactureOrNull
type ManufactureOrNull = OrNull<Manufacture>;
const manufacture: ManufactureOrNull = 'Apple';
你会看到在使用 OrNull
这个 Utility Types 是,就像呼叫一个 function 一样,我们把 Manufacture
当成参数透过 <>
传入 OrNull
中,而它会回传一个新的型别给我们。
ManufactureOrNull
实际上的值其实也就是 'Apple' | 'Google' | 'Samsung' | 'Sony' | null
,虽然 OrNull
这个 Utility Types 看起来很鸡肋,但有时其实还蛮好用的,因为它会让我们的程序看起来比较乾净一些:
function getManufacture(manufacture: Manufacture | null) {
/*...*/
}
function getManufacture(manufacture: OrNull<Manufacture>) {
/*...*/
}
举例来说,上面这两个 function 对於参数 manufacture
的型别定义虽然一样,但後者个人看起来就更工整了一些,而不会有一种 null
是多加出来的感觉。
再来一样是官方有说明到的 OneOrMany
,写法是这样:
// Utility Type
type OneOrMany<Type> = Type | Type[];
使用上像这样:
type Manufacture = 'Apple' | 'Google' | 'Samsung' | 'Sony';
// 使用 OneOrMany 这个 Utility Type 产生新的型别 ManufactureOrManufactures
type ManufactureOrManufactures = OneOrMany<Manufacture>;
const manufactures: ManufactureOrManufactures = ['Apple', 'Google'];
这里一样可以看到,我们把 Manufacture
当成参数一样从 <>
传进 OneOrMany
这个 Utility Type 中,并得到新的 ManufactureOrManufactures
型别,它的值只要满足 Manufacture
或者是 Manufacture[]
都可以。
Utility Types 就像函式一样,所以也可以一个 Utility Type 包着另一个 Utility Type,例如:
// Utility Type
type OneOrManyOrNull<Type> = OrNull<OneOrMany<Type>>;
这里 OneOrManyOrNull
是一个 Utility Type,而它是透过 OrNull
和 OneOrMany
同时组合出来的,使用的方式一样:
type Manufacture = 'Apple' | 'Google' | 'Samsung' | 'Sony';
// 使用 OneOrManyOrNull 这个 Utility Type 产生新的型别 OneOrManyOrNullOfManufacture
type OneOrManyOrNullOfManufacture = OneOrManyOrNull<Manufacture>;
const manufacturesData: OneOrManyOrNullOfManufacture = null;
这里一样可以把 Manufacture
当成参数一样传入 OneOrManyOrNull
这个 Utility Type 中,现在 OneOrManyOrNullOfManufacture
指的就会是 Manufacture | Manufacture[] | null
。
从上面的几个例子中,相信读者应该可以感受到 Utility Types 能够像 function 一样,输入 input 并取得 output 的感觉,只是 input 和 output 都需要是 TypeScript 的型别。
让我们回顾一下昨天的 getObjValue
这个函式,实际上如果不管函式本身,针对物件型别也是可以建立出几个不同的 Utility Types。
这里我们先建立一个物件型别作为後面的范例:
type Manufacture = 'Apple' | 'Google' | 'Samsung' | 'Sony';
type Product = {
name: string;
price: number;
manufacturer: Manufacture;
isLaunched: boolean;
};
建立一个 Utility Type 来取出所有物件型别的 keys 且只要 string
:
// Utility Type
type Keys<T> = keyof T & string;
使用的方式:
type KeysOfProduct = Keys<Product>; // "name" | "price" | "manufacturer" | "isLaunched"
这时候 KeysOfProduct
的结果会是 "name" | "price" | "manufacturer" | "isLaunched"
。
读者可以注意到,Product
这个物件型别一样可以被当成参数一样传入 Keys
这个 Utility Type 的 <>
内。
Values
这个 Utility Type 则是可以取出物件型别的所有属性值(型别),读者们可以根据昨天的练习试着自己写写看:
// Utility Type
type Values<T> = T[keyof T];
使用的方式一样可以把物件型别 Product
当成参数带入:
type ValuesOfProduct = Values<Product>; // string | number | boolean
最後会得到新的型别 ValuesOfProduct
。
最後来写一个 Utility Type,它的作用是取出物件型别中的某个 key 的属性值(型别),读者们一样可以根据昨天的内容试着练习看看:
// Utility Type
type PickObj<T, U extends keyof T> = T[U];
这里一样要记得 U extends keyof T
的使用,如果没有限制泛型 U
一定要是物件型别 T
的 key,TypeScript 因为没办法确保能在 T
中找到 U
这个 key,将会报错:
使用上则是可以同时带入两个型别参数:
type Price = PickObj<Product, 'price'>; // number
如此就可以取出物件型别中 key 为 price
的属性值的型别。
今天提到的一些 Utility Types 多半还蛮直观的,甚至可能会觉得可有可无,重点是让读者先对於可以把 Type 当成 function 一样使用有些感觉,後面当我们学到 Conditional Types、Mapped Types 等等更进阶的用法後,你将会发现「Wow!原来型别还可以这样『玩』!」。
这里提供一些未来在学习 Utility Types 是,方便好用的小技巧:
https://tsplay.dev/mLRnew @ TypeScript Playground
>>: ASP.NET MVC 从入门到放弃(Day17)-MVC控制器(Controller)介绍
前言 今天来介绍我个人很常用的小撇步,关於 OR (||) 与 AND (&&),除...
前言 Debian 也在这几天释出第 11 版,开发代号 bullseye,是目前的稳定 (Stab...
上一篇的 repository 还欠一个 mapper 把 EtaResponse 转成 EtaRe...
1.下载 https://tortoisesvn.net/downloads.html 2.安装 :...
历史背景 1990年代,是灰色缉毒犬PC防毒,回纹针干扰文书,Internet Explorer 还...