2021-07-15 系统化装修 2021-03-15 学习TS handBook V2 系统回顾 2019-12-11 初稿 /frontEndBasic/typescript

Typescirpt ts 一本通 - 图1

0 存在的意义

对前端最大的意义是:重塑类型思维。时刻把我类型进行代码约束。

官方文档这样介绍:

TypeScript 是一个开源的编程语言,通过在 JavaScript(世界上最常用的语言之一) 的基础上添加静态类型定义构建而成。 类型提供了一种描述对象形状的方法。可以帮助提供更好的文档,还可以让 TypeScript 验证你的代码可以正常工作。

在 TypeScript 中,不是每个地方都需要标注类型,因为类型推断允许您无需编写额外的代码即可获得大量功能。

1 安装、配置、使用

专门搞了一个仓库 https://gitee.com/xiaoxfa/review-ts

  1. touch index.ts
  2. npx tsc --init # 生成tsconfig.json 具体看最下面章节
  3. npx tsc src/1.ts

多种方式:

  • tsc tsc HelloWorld.ts --strict --alwaysStrict false --watch
  • ts-node a.js 全局依赖
  • node --experimental-loader esbuild-node-loader file.ts 用到了一个基于 esbuild 的loader,推荐下面的简单
  • npx esno a.ts 如果是 node CJS 模块
  • npx esmo a.ts 如果是 esm 并且 type:module
  • 使用babel

2 ts 入门

image.png

基本类型

ts可以指定和推断基本类型,这个比较简单,放几个代码片段做说明。

需要强调的是,对于基本类型,实际中不需要声明,直接推断即可。

  1. // number string boolean
  2. const num: number = 5
  3. const name1: string = "xinbao"
  4. // Array 两种写法
  5. const list1: number[] = [1, 2, 3] // 常规
  6. const list2: Array<number> = [1, 2, 3] // 数组泛型
  7. const list3: Array<number | string> = [1, 2, 3, "4"]
  8. // tuple 元组 就是有要求的数组,定义了内部的结构类型
  9. let x: [string, number]
  10. // object
  11. let obj1: { id: number; y: number } = { id: 1, y: 2 }
  12. // any
  13. // void
  14. // Null Undefined
  15. const u: undefined = undefined;
  16. const n: null = null;
  17. // never 永不存在的值类型。返回值是抛出异常,不会有返回值的函数表达式,箭头函数的返回值类型
  18. // 类型断言 type assertions 明确知道结构
  19. // let slen: number = (<string>sV).length;
  20. let slen: number = (sV as stirng).length;

枚举 Enum

把一组数值 变为 有意义的名字。用途:抽离魔法常量,单独维护,节省记忆成本

  1. enum Color {
  2. Red = 1,
  3. Green = 2,
  4. Blue = 4
  5. }
  6. let c: Color = Color.Red // 1
  7. // 也可以反查
  8. let name:string = Color[2]
  9. name // Green

也可以改为通过普通对象进行映射。

Interface & Type

两者都是实现对对象的类型定义,不会参与编译,再开发阶段起辅助作用。

Interface

  1. interface Data {
  2. name: string;
  3. age?: number; // 可选属性
  4. [x: string]: any; // 字符串索引签名
  5. readonly id: number; // 只读
  6. }
  7. // 场景:对参数进行约束
  8. function fun(persion: Data){
  9. return persion.name
  10. }

Type

可以约束简单值,也可以约束其他类型。一定程度上可以混用。

  1. type Label = 'a'|'b';
  2. type Add = (x: number, y: number) => number
  3. let add: Add = (a, b) => a + b
  4. // 混合接口
  5. interface Lib {
  6. label:Label;
  7. version: string;
  8. dost(): void;
  9. }

小技巧:遍历 Interface 里的 key 值 ,得到属性集合。具体详见下面工具方法部分。

  1. interface Person{ a:string; b:number}
  2. type K1 = keyof Person; // 'a'|'b'

interface 和 type 的关系

interface 和 type :

  • interface 和 type 都可以定义类型,通用
  • interface extends , interface A & B 和 type & typeB 效果一致

不同之处:

Type aliases and interfaces are very similar, and in many cases you can choose between them freely. Almost all features of an interface are available in type, the key distinction is that a type cannot be re-opened to add new properties vs an interface which is always extendable. Type和 Interface 非常相似,很多时候可以自由选择。interface的大多数特性type也有,不同之处在于: type 不能被重新补充新的属性,而interface可以extends拓展新属性。

这里是指type本身不能重新覆盖、新增,如果是另起一个新类型不会有问题。见 Demo

函数

就函数重载说一下。

  1. // 函数重载
  2. function add8(...rest: number[]): number
  3. function add8(...rest: string[]): string
  4. function add8(...rest: any[]): any {
  5. let first = rest[0]
  6. if (typeof first === "string") {
  7. return rest.join("")
  8. }
  9. if (typeof first === "number") {
  10. return
  11. }
  12. }

也包含了 继承 抽象 接口 setter getter等。这里内容其实比较多,本次先忽略了。

抽象类 多态

泛型 generics

实现一个打印函数,传入啥就打印啥。

  1. // 可以使用联合类型
  2. function log_a(value: string | string[]): string | string[] {
  3. return value
  4. }
  5. // 或者 any 搞定,但这样丢失了一些信息,不知道约束关系
  6. function log_b(value: any):any {
  7. return value
  8. }
  9. // 如果使用泛型就简单了,传入T 返回T
  10. function log<T>(value: T): T {
  11. return value
  12. }
  13. log<string[]>(["1"])

类型推断

会自动进行推断,从右到左。
上下文类型推断。还可以 as,还可以 <>

基本概念就都结束了。

3 tsconfig.json

这里请忽略,直接跳过!
详情 https://www.staging-typescript.org/tsconfig
本身是一个json,拉钩上的文章解析:其他人的解析

类型 描述 备注
compilerOptions编译选项
基础选项
incremental true/default 增量编译
target es5/default 编译成啥版本 es3/es5/es2015/es2016/…/esnext
module commonjs 代码生成格式 none/commonjs/amd/system/umd/es2015/es2020/esnext
lib [] 指定编译包含的类库文件
allowJs true 是否允许js参与编译
checkJs true 是否检查js报错
jsx preserve 保持现状 设置jsx代码生成 preserve/react-natice/react/react-jsx/react-jsxdev
declaration true 生成对应的 .d.ts 文件
declarationMap true 生成 .d.ts 的 sourcemap文件
sourceMap true 生成 souecemap
outFile ./ 输出文件
outDir ./ 输出目录
rootDir ./ 设定根目录
composite true 启用项目编译
tsBuildInfoFile ./ 设定文件保存增量编译信息
removeComments true 移除注释
noEmit true 不输出 不生成文件,只检查vue-tsc
importHelpers true 从 tslib 引入helper
downlevelIteration true 在早期版本中提供对迭代/展开/解构的支持 es3/es5
isolatedModules true 传输每一个文件作为一个分离的模块 类似ts.transpileModule
严格类型检查选项
strict true 启用全部严格类型检查选项 一定打开
noImplicitAny true 禁止隐式 any 类型 一般做不到,看权衡
strictNullChecks true 严格null检查
strictFunctionTypes true 检查函数类型
strictBindCallApply true 更严格地检查 call、bind、apply 函数的调用 不太理解
strictPropertyInitialization true 类的初始化属性严格检查
noImplicitThis true 禁止隐式 this 类型
alwaysStrict true 每个文件添加 use strict 启用严格模式
额外的检查
noUnusedLocals true 未使用的本地数据报错
noUnusedParameters true 未使用的参数报错
noImplicitReturns true 禁止隐式返回。如果代码的逻辑分支中有返回,则所有的逻辑分支都应该有返回。
noFallthroughCasesInSwitch true switch 要有失败分支
noUncheckedIndexedAccess true 在索引签名结果中包含 undefined
noImplicitOverride true Ensure overriding members in derived classes are marked with an ‘override’ modifier.
noPropertyAccessFromIndexSignature true Require undeclared properties from index signatures to use element accesses.
模块解析选项
moduleResolution node 模块解析策略 一般选node
bseUrl ./ 解析非绝对路径模块名时的基准目录
paths {} 可理解为 webpack 的 alias 别名配置 “@src/“: [“src/“],
rootDirs [] 指定多个目录作为根目录
typeRoots [] 指定类型文件的根目录
types [] 默认情况下,所有的 typeRoots 包都将被包含在编译过程中
allowSyntheticDefaultImports true 允许合成默认导出 dayjs?
esModuleInterop true Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies ‘allowSyntheticDefaultImports’. 和上面同时开启
preserveSymlinks true 不解析symlinks真实路径
allowUmdGlobalAccess true 允许从模块中访问umd全局变量
sourceMap选项
sourceRoot ‘’ Specify the location where debugger should locate TypeScript files instead of source locations.
mapRoot ‘’ Specify the location where debugger should locate map files instead of generated locations.
inlineSourceMap true Emit a single file with source maps instead of having a separate file.
inlineSources true Emit the source alongside the sourcemaps within a single file; requires ‘—inlineSourceMap’ or ‘—sourceMap’ to be set.
实验性选项
experimentalDecorators true 开启es7的decorators装饰器 用了装饰器一定开这个
emitDecoratorMetadata true 支持 metadata
高级选项
skipLibCheck true 跳过检查声明文件
forceConsistentCasingInFileNames true 不允许对同一文件的大小写不一致的引用

除了 compilerOptions,还有include/exclude/files/extends

一般不用管。

4 工具类

使用场景有很多,比如在项目中需要输入框、异步请求、数据展示,对于其中的很多字段是重复出现的,如果刻意联系,可以重新组织这些对应的类型。如果一个字段变了,相关联的字段会报错,一次改动,多处报错,依次解决就可以。

实际来看,如果不是代码洁癖,可以不使用这些。有些面试还会问常用工具类的底层实现,这个见仁见智吧。

keyof

可以通过 keyof获得一个类型里的 propName,刚才提过。

  1. interface Point {
  2. a1:string;
  3. a2:number;
  4. }
  5. type R= keyof Point
  6. const r:R='a1'

方便约束传参。

element-plus

  1. import { ElForm } from 'element-plus'
  2. // 这时候 ElForm 是一个对象

typeof

js里有,ts里有特殊含义,可以约束类型.
typeof 对象,获取对象表示的类型。

  1. let s = "hello";
  2. let n: typeof s = 'fff' // 动态约定
  3. // 简单的config可以不抽取类型
  4. const baseInfo={name:'',age:1}
  5. const me:typeof baseInfo={
  6. name:'',
  7. age:2
  8. }

还有一个常见的用法

  1. type Info = keyof typeof me // 先转成类型,再读取类型的key // name age

ReturnType

函数返回值

  1. function f() {
  2. return { x: 10, y: 3 };
  3. }
  4. // 可以获得返回值的类型
  5. type P = ReturnType<typeof f>; // 两者一致
  6. type R = {
  7. x: number;
  8. y: number;
  9. }

还有有很多内置的工具类,简单一提:

  • Partial<Type>把type里的类型变为可选
  • Required<Type>反过来,都是必选
  • Readonly<Type> 设定只读
  • Record<Keys, Type>,映射场景vue 路由
  1. interface Conf{
  2. name:string;
  3. path:string;
  4. }
  5. type Keys = 'index'|'list'
  6. const f:Recrod<Keys,Conf>={
  7. index:{name:'',path:''},
  8. list:{name:'',path:''}
  9. }
  • Pick<Type,Keys>从一个大的type里挑几个类型,组成新的
  • Omit<Type, Keys> 从一个大的类型里删几个类型,组成新的
  • Exclude<Type, ExcludedUnion>给多个类型,取不重复的 type T1 = Exclude<"a" | "b" | "c", "a" | "b">得到 'c'
  • Extract<Type, Union>给多个类型,取重复的类型
  • NonNullable<Type>去掉 nullundefined 干净的类型
  • Parameters<函数> 看函数的入参类型,本身是个数组
  • InstanceType<T> 获取构造函数类,实例类型组成的类型

ts工具函数.png

声明文件

jquery是amd类库。jquery不支持ts,需要声明文件。

  1. npm i @types/jquery -D

DefinitelyTyped 是最大的公共存储库,包括1000多个库文件。也有一个用来管理 TypeScript 定义的 Node.js 流行模块,叫 Typings。

如何写声明文件。

*.d.ts

  1. declare function globalLib(options:flobalLb.Options):viod

实战

  • 最佳实践
    • 使用场景
    • vue实战
      • vue2.x + ts 经验小结
      • 系统中的ts和lint vue2.x+ts
    • Node实战

公司用了 swagger 想自动生成 ts 类型改怎么做?

目前有两个技术选型,自己看着来

参考链接

当你需要对js运行时进行检查,可以参考这篇文章 TypeScript 运行时类型检查指南,这是一篇翻译文章,暂时用不到。

写在最后

那几年成长真的好慢,很早就尝试过ts,但是搞不懂工程化,白蹉跎了那段好时光。

image.png