美文网首页TypeScript基础
探索 TypeScript 类型注解 - 类型编程

探索 TypeScript 类型注解 - 类型编程

作者: zhilidali | 来源:发表于2020-01-11 19:24 被阅读0次

    Exploring TypeScript Type Annotations - Type Programming

    本文由 WowBar 团队首发于 GitHub

    作者: zhilidali

    欢迎来到 《探索 TypeScript 类型注解》 系列教程。

    上一篇介绍了 TS 的高级类型。
    本篇将前面的知识点融会贯通,将对类型的探索提升一个层次:从类型层面进行编程。

    目录

    类型编程

    首先,我们回顾一下前几节对类型的探索。

    • 通过数据类型,我们了解到 TS 支持的数据类型。
      • 支持 JS 数据类型。
      • 新增一些数据类型。
    • 通过自定义类型,我们了解到如何声明或命名一个类型。
      • 接口, interface 来声明各种复杂数据类型。
      • 类型别名, type 对类型进行命名。
      • 泛型,<T> 如同 JS 中函数将类型作为参数传递。
    • 通过类型检查,我们了解到类型与 JS 之间的各种交互。
      • 类型推断,通过 JS 的值推断出相应的类型。
      • 类型断言,直接对 JS 中的值指定一个类型。
      • 类型兼容,由类型之间的关系反映出 JS 值之间的关系。
      • 类型保护,通过 JS 中的操作符来反映出精确的类型。
    • 通过高级类型,我们了解到 TS 提供的各种类型操作符。
      • 交叉类型,使用类型操作符 &
      • 联合类型,使用类型操作符
      • 索引类型,使用类型操作符 keyofT[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 中排除 nullundefined

    使用示例

    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

    typeof

    在 TS 中,还可以使用 typeof 来获取变量的类型。

    let foo: number = 3;
    type bar = typeof foo; // 相当于 type bar = number
    

    extends

    前面的章节中多处使用了 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

    1. extends 关键字的语义:它们之间属于继承关系,即子类(型)继承超类(型)。
    2. 从类型兼容性角度:超类型兼容子类型,即子类型可以赋给超类型。
    3. 从功能上:
      • 类和接口中的 extends 用来定义,可有多个超类 Sup,中间用 , 分割。
      • 泛型约束和条件类型中的 extends 用来检测兼容性,即 Sup 是否兼容 Sub

    类型与集合

    既然是编程,下面从数学的角度来简单粗略地描述 TS 的类型系统,(读者可略过,想深入的童鞋可移步:https://zhuanlan.zhihu.com/p/38081852)。

    TS 中的类型好比数学中的集合,类型是具有某种特定性质的 JS 值的集合。
    比如 number 类型对应 JS 中所有数值的集合。

    类型集合的分类

    • any 类型对应为 全集
    • never 类型对应为 空集
    • 联合类型是类型集合之间的 并集
    • 交叉类型是类型集合之间的 交集

    结语

    本篇主要是对类型进行编程的能力进行了梳理。

    协议

    本作品采用知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议进行许可。

    《探索 TypeScript 类型注解》

    相关文章

      网友评论

        本文标题:探索 TypeScript 类型注解 - 类型编程

        本文链接:https://www.haomeiwen.com/subject/lksbactx.html