Exploring TypeScript Type Annotations - Type Programminghtml
做者: zhilidaligithub
欢迎来到 《探索 TypeScript 类型注解》 系列教程。算法
上一篇介绍了 TS 的高级类型。 本篇将前面的知识点融会贯通,将对类型的探索提高一个层次:从类型层面进行编程。typescript
首先,咱们回顾一下前几节对类型的探索。编程
interface
来声明各类复杂数据类型。type
对类型进行命名。<T>
如同 JS 中函数将类型做为参数传递。&
|
keyof
,T[K]
in
T extends U ? X : Y
infer
is
操做符以及上面所介绍的 typeof
根据 TS 提供的 数据类型 以及声明的自定义类型,结合高级类型中的 操做符 能够对类型进行各类运算 (高级类型本质上就是各类操做符表达式)。数据结构
再加上具备函数功能的 泛型,能够对类型的运算进行封装、复用、组合。要知道函数是 JS 中最强大的武器,谁说“类”来着,算了,好累,我还要(搬砖)拯救世界。还要知道,TS 没有采用传统面向对象语言使用的名义类型,而是基于偏向于函数式编程的结构类型,(JS 是多范式编程语言)。编程语言
到此为止,咱们已经具有了对类型进行编程的各类工具 (程序 = 数据结构 + 算法),接下来各位童鞋就能够发挥无穷的智慧了。函数式编程
童鞋请留步!俗话说吃人嘴短,拿人手软,请先让巨硬(微软大大)炫个富。下面介绍 TypeScript 官方标准库中封装的实用工具类型。函数
TypeScript 提供的实用工具类型用来实现常见的类型转换,这些类型工具函数是全局可见的。
Extract,Exclude,NonNullable
Extract<T, U>
:从 T
中提取能够赋值给 U
的类型Exclude<T, U>
:从 T
中排除能够赋值给 U
的类型NonNullable<T>
:从 T
中排除 null
和 undefined
使用示例
type foo = Extract<number | string, string>; // string
type bar = Exclude<number | string, string>; // number
type baz = NonNullable<number | string | null | undefined>; // string | number
复制代码
具体实现
// 主要使用条件类型 `T extends U ? X : Y` 实现
type Extract<T, U> = T extends U ? T : never;
type Exclude<T, U> = T extends U ? never : T;
type NonNullable<T> = T extends null | undefined ? never : T;
复制代码
Partial, Require, Readonly
Partial<T>
:将 T
中的全部属性设置为可选Require<T>
:将 T
中的全部属性设置为必选Readonly<T>
:将 T
中的全部属性设置为只读使用示例
interface Type { a: number, b?: string };
let foo: Partial<Type> = { b: 'b' };
let bar: Required<Type> = { a: 1 }; // Error
let baz: Readonly<Type> = { a: 1 };
baz.a = 2; // Error
复制代码
具体实现
// 主要使用映射类型 `[K in T]: Type` 及索引类型 `keyof T`、`T[P]` 实现
type Partial<T> = { [P in keyof T]?: T[P] };
type Require<T> = { [P in keyof T]-?: T[P] }; // 注意这里的 `-?`
type Readonly<T> = { readonly [P in keyof T]: T[p] };
复制代码
TypeScript 标准库中提供了许多实用的工具类型,并且随着 TypeScript 不断更新迭代,会有更多的实用工具类型加入到标准库中,此处不在重复介绍(提示:实用工具很实用),详情请移步官方手册,手册中给出了详细的使用示例。对于这些工具类型的具体实现,请移步官方仓库的 lib。
在 TS 中,还能够使用 typeof
来获取变量的类型。
let foo: number = 3;
type bar = typeof foo; // 至关于 type bar = number
复制代码
前面的章节中多处使用了 extends
关键字。以下
原生 JS 中类的继承
class A { a: number }
class B extends A { b: string } // B 继承 A
let a: A = new A();
let b: B = new B();
a = b; // Ok, A = B 少兼容多,子类兼容超类
复制代码
接口继承
interface A { a: number }
interface B extends A { b: string }
let a: A = { a: 1 };
let b: B = { b: 'b', a: 1 };
a = b; // Ok, A = B
复制代码
泛型约束
interface A { a: number }
let foo: <B extends A>(arg: B) => void;
foo({ a: 1, b: 2});
复制代码
条件类型
interface A { a: number }
interface B { a: number, b: string }
type E = B extends A ? true : false;
// type E = true
复制代码
汇总以下
class SubClass extends SupClass
interface SubType extends SupType {}
<T extends U>
T extends U ? X : Y
以上均有共同的形式 Sub extends Sup
extends
关键字的语义:它们之间属于继承关系,即子类(型)继承超类(型)。extends
用来定义,可有多个超类 Sup
,中间用 ,
分割。extends
用来检测兼容性,即 Sup
是否兼容 Sub
既然是编程,下面从数学的角度来简单粗略地描述 TS 类型系统,(读者可略过,想深刻的童鞋可移步:zhuanlan.zhihu.com/p/38081852)。
TS 中的类型比如数学中的集合,类型是具备某种特定性质的 JS 值的集合。 好比 number
类型对应 JS 中全部数值的集合。
类型集合的分类
any
类型对应为 全集。never
类型对应为 空集。本篇主要是对类型进行编程的能力进行了梳理。
本做品采用知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议进行许可。