分享好友 站长动态首页 网站导航

TypeScript 类型体操指北

网友发布 2022-10-26 20:41 · 头闻号编程技术

最近公司组织技术分享,作为一个懒癌患者,终于可以更新一下了
前言常见类型概览常见类型列举基础类型string一般指是字符串类型的总称例如:"Hello, world"模板字符串类型模板字符串类型 最早从 TS 4.1 版本开始出现,并在后续版本中不断增强。 一般为如下形式:type World = "world";type Greeting = `hello ${World}`;number一般指数字类型的总称,包含 intfloatboolean一般指 truefalse 的总称复合类型通用 K/V 结构一般形如下述结构:// interfaceinterface MyKVStructure {[key in string | number | symbol]: any;}// type aliastype MyKVStructure = {[key in string | number | symbol]: any;}显然 通用 K/V 结构 包含两个可供设置类型的「槽位」[^5],其中「键」类型只能为stringnumbersymbol,而「值」类型理论上可以为任何类型。

补充阅读:Differences Between Type Aliases and InterfacesArray、Tuple泛型「泛型」一般指的是在程序编码中一些包含类型参数的类型 例:// 这里的 T 就是类型参数interface MyType {a: T}在某些简单的场景下,我们也可以把它作为「类型模板」来用函数类型常见的形如 => R 的结构 函数有如何几种常见声明方式:

type

MyFunction

=

=>

void

;

interface

MyFunction

{

:

void

;

}

type

MyFunction

=

{

:

void

;

}

各类型常见场景基础类型常见场景stringnumberboolean 这类基础类型常用于「声明变量」Array、TupleFunction结构化类型系统读完上述内容后,部分读者会好奇为何文章要强调 K/V 结构,而非直接用 object 来代指。

实际上 Typescript 遵循的是「结构化类型」规范,也就是人们常说的「鸭子类型」。 换言之,针对 K/V 结构类型,只要满足「给定结构兼容」,那么就可以判定二者兼容。详见 typescript handbook structural-type-systemSubtypeAssignment在官网的解释中,Typescript 存在两种「类型兼容」方式:SubtypeAssignment

... In Typescript, there are two kinds of compatibility: subtype and assignment ...
Assignment 详细规则见下表: Ts与集合名词类比对照表
名词集合Typescript
包含于extends
交集&
并集|
空集never
全集Uunknown
类型推导基本运算集合运算A B使用 extends 关键字 例:type TestUnknown = T extends unknown 'Y' : 'N';type TestNever = T extends never 'Y' : 'N';// 任何集合都包含于全集TestUnknown; // Y// 任何集合都不包含于空集TestNever; // N
A B使用 & 符号A ∅ = ∅例:// 任何集合与空集的交集都是空集type Test = string & never; // neverA U = A例:

// 任何集合与全集的交集都是自己

type

Test

=

string

&

unknown

;

// string

常见运用
  1. 利用 unknown 剔除「交叉类型」中某些不需要的类型
  2. 利用 never 实现「一着不慎,满盘皆输」的判断操作(例如 js 中 Array.prototype.some 的表现)
  3. | 联合使用实现批量过滤
A B使用 | 符号A U = U例:// 任何集合与全集的并集都是全集type Test = { b: number } | unknown; // unknownA ∅ = A例:// 任何集合与空集的并集都是自己type T1 = string | never; // { b: number }常见运用
  1. 剔除「联合类型」中某些不需要的类型,常见使用范例如:某些「内置范型操作符」:ExcludeExtractOmit
  2. 利用 unknown 实现「一着不慎,满盘皆输」的判断操作(例如 jsArray.prototype.some 的表现)
  3. & 联合使用实现批量过滤
条件运算在常见的编程语言中,我们常常使用 if ... else 或者「三元运算」来实现「条件运算」。

「三元运算」在常见编程语言中有一个固定的格式:条件表达式 表达式1 : 表达式2Typescript 类型系统中,我们同样使用类似「三元运算」的方式来实现「条件运算」,这被称为 Conditional Types「条件表达式」本质上最终会返回 boolean 类型值,在 Typescript 类型系统中,依然遵循此规则。在 typescript 中常常使用 例:type MyType = true extends boolean 'Y' : 'N'; // Y循环/遍历在常见的编程语言中,我们常常需要对 ArrayTuple 结构进行 循环/遍历,语言本身也内置了很多方法帮助我们完成这样的需求。但是在 Typescript 类型系统 中,并不支持这样直接地 循环/遍历 像 ArrayTuple 这样的结构。Union Type古怪 表现type MapType = { a: T };type MapTypeByConditionalType = T extends any { a: T } : never;type TT = MapType; // { a: string | number; }type TT = MapTypeByConditionalType; // { a: string } | { a: number }我们发现 Union Type 在经过某些 泛型操作符 后 "裂开了" Union Type 更像是一个「非空有序集合」下述为 type T = string | numberAST 描述:再来看一下 getIn 的入参校验:解题思路:get 方法比较简单,直接使用 function 的反向类型推导,根据入参 K ,取出返回值 T[K] 的类型


getIn 方法比 get 方法稍复杂一些,我们需要一个包含所有 key 的组合 联合类型

例如:interface Obj { a: string; b: {c: number }}上述这样一个结构,我们希望生成:["a"] | ["b", "c"] 这样的一个 联合类型 。要完成上述需求,我们需要:

  1. 递归地暴力枚举所有的 key 和 value
  2. 判断 value 如果是非嵌套类型,那么把对应的 key push 到上一次的 tuple 里,如果依然是嵌套类型,那么继续递归下去
Tips:这里为了简化代码,会用到一个作者自己封装的库 :

具体功能就是用ts的类型系统实现类似 js 原生的 api 的工具函数,有兴趣可以了解一下,这里我们会用到 push 功能来实现最终结果的收集。
getByKeyPathStr 方法就很简单了,我们只需要基于 getIn 方法,使用类似 join 的操作,把入参的 ["a"] | ["b", "c"] 转换为 "a" | "b.c" ,这里为了简化代码,还是用到了 todash 中的 join 方法。总结
  1. 这里用到了文章最初讲到的 递归、暴力枚举类型。

  2. 这里利用了联合类型的 非空、有序、唯裂开的特性。
  3. 上述代码为了利于讲解,去除了js逻辑部分,有兴趣的同学可以补齐。
  4. 上述代码中 getIngetByKeyPathStr 方法为了简化场景,只完成了入参部分的类型推导,有兴趣的同学可以补齐返回值部分。

  5. 入参类型推导其实还有缺陷,实际应为 ["a"] | ["b"] | ["b", "c"] ,但改动其实不大,有兴趣的同学可以修正一下。
Q&A为什么同样是 declare 声明的类型,有时在全局生效,有些只能在局部生效?
  1. 首先确保你自定义的类型均已被 ts 加载
  2. 检查你所编写的内容属于「脚本」还是属于「模块」,常见区分方法为:使用了 importexport 关键字则为「模块」。详见「typescript handbook」#modules
  3. 如果是「脚本」,直接 declare 即可在全局生效,若为「模块」,则仅在局部生效
【接上】「模块」内如何声明/扩展全局类型?declare global {interface String { // ...}}详见「typescript handbook」#global modifying module【接上】「脚本」内如何引入其他类型?// 如果是 类库/// // 如果是 自定义文件/// 详见「typescript handbook」#reference types如何扩展一个库/模块内部的类型?详见官方文档我是一个伸手党,我想拿来就用,除了官方内置的泛型操作符有没有其他现成好用的库?为什么有些人觉得 ts 很难学/难用?常见原因: 解决方案
  1. 请阅读文档
  2. 请仔细阅读文档
  3. 请熟读并背诵文档

名词解释
反对 0
打赏 0
更多相关文章

评论

0

收藏

点赞