导航
[封装01-设计模式] 设计原则 和 工厂模式(简单抽象方法) 适配器模式 装饰器模式
[封装02-设计模式] 命令模式 享元模式 组合模式 代理模式
[React 从零实践01-后台] 代码分割
[React 从零实践02-后台] 权限控制
[React 从零实践03-后台] 自定义hooks
[React 从零实践04-后台] docker-compose 部署react+egg+nginx+mysql
[React 从零实践05-后台] Gitlab-CI使用Docker自动化部署
[源码-webpack01-前置知识] AST抽象语法树
[源码-webpack02-前置知识] Tapable
[源码-webpack03] 手写webpack - compiler简单编译流程
[源码] Redux React-Redux01
[源码] axios
[源码] vuex
[源码-vue01] data响应式 和 初始化渲染
[源码-vue02] computed 响应式 - 初始化,访问,更新过程
[源码-vue03] watch 侦听属性 - 初始化和更新
[源码-vue04] Vue.set 和 vm.$set
[源码-vue05] Vue.extend
[源码-vue06] Vue.nextTick 和 vm.$nextTick
[源码-react01] ReactDOM.render01
[源码-react02] 手写hook调度-useState实现
[部署01] Nginx
[部署02] Docker 部署vue项目
[部署03] gitlab-CI
[深入01] 执行上下文
[深入02] 原型链
[深入03] 继承
[深入04] 事件循环
[深入05] 柯里化 偏函数 函数记忆
[深入06] 隐式转换 和 运算符
[深入07] 浏览器缓存机制(http缓存机制)
[深入08] 前端安全
[深入09] 深浅拷贝
[深入10] Debounce Throttle
[深入11] 前端路由
[深入12] 前端模块化
[深入13] 观察者模式 发布订阅模式 双向数据绑定
[深入14] canvas
[深入15] webSocket
[深入16] webpack
[深入17] http 和 https
[深入18] CSS-interview
[深入19] 手写Promise
[深入20] 手写函数
[深入21] 数据结构和算法 - 二分查找和排序
[深入22] js和v8垃圾回收机制
[深入23] JS设计模式 - 代理,策略,单例
[深入24] Fiber
[深入25] Typescript
[前端学java01-SpringBoot实战] 环境配置和HelloWorld服务
[前端学java02-SpringBoot实战] mybatis + mysql 实现歌曲增删改查
[前端学java03-SpringBoot实战] lombok,日志,部署
[前端学java04-SpringBoot实战] 静态资源 + 拦截器 + 前后端文件上传
[前端学java05-SpringBoot实战] 常用注解 + redis实现统计功能
[前端学java06-SpringBoot实战] 注入 + Swagger2 3.0 + 单元测试JUnit5
[前端学java07-SpringBoot实战] IOC扫描器 + 事务 + Jackson
[前端学java08-SpringBoot实战总结1-7] 阶段性总结
[前端学java09-SpringBoot实战] 多模块配置 + Mybatis-plus + 单多模块打包部署
[前端学java10-SpringBoot实战] bean赋值转换 + 参数校验 + 全局异常处理
[前端学java11-SpringSecurity] 配置 + 内存 + 数据库 = 三种方式实现RBAC
[前端学java12-SpringSecurity] JWT
[前端学java13-SpringCloud] Eureka + RestTemplate + Zuul + Ribbon
(一) 前置知识
(1) 一些单词
vite 快点
declare 声明
interop 相互操作 // esModuleInterop=true 表示commonjs模块可以使用import和require两种语法
primavera 青年队 春天
survey 调研 调查 测量
preserve 保留 保护
implicit 隐式 // noImplicitAny 不包含隐式的any,即any报错
synthetic 合成的 人造的 // React.BaseSyntheticEvent 合成事件
acquisition 收购 得到 // typeAcquisition 如何得到.d.ts类型
(2) 如何安装typescript
cnpm install typescript -g
(3) tsc 命令
- tsc命令官方文档
- 当安装了typescript后,就可以使用
tsc命令了 - 命令具体分了很多类,比如 compilerOptoin, buildOption, watchOption
tsc index.ts // 编译由tsconfig.json定义的项目中的index.ts文件
tsc src/*.ts // 编译所有scr中的ts文件
tsc --project tsconfig2.json // 指定具体的tsconfig.json文件中的配置来编译
compilerOption
tsc --init // 初始化typescript项目,并生成一个tsconfig.json文件
tsc --all // 显示所有编译器命令选项
tsc --version // 打印编译器的版本信息
(4) keyof索引类型查询,T[K]索引访问
- keyof
- 索引类型查询 - 操作符
对于任何 ( 类型T ),( keyof T ) 返回T上已知的公共 ( 属性名 ) 的 ( 联合类型 )
- T[K]
- 索引访问 - 操作符
- 返回接口中对应的 keyof T 索引对应的类型
interface Person {
name: string;
age: number;
location?: string;
}
type K1 = keyof Person; // "name" | "age" | "location"
type K2 = keyof Person[]; // "length" | "push" | "pop" | "concat" | ...
type K3 = keyof []; // "length" | "push" | "pop" | "concat" | ...
type K3 = keyof { [x: string]: Person }; // string | number
(5) typeof类型保护,instanceof类型保护
- typeof
- 类型保护
- typeof 特点
- typeof 在 JS 中可以判断数据类型
typeof 在 TS 中用来获取 ( 变量的声明类型 ),主要针对 ( 对象 ) 和 ( 函数 )
- instanceof
- 类型保护
- instanceof 类型保护是通过 ( 构造函数 ) 来细化类型的一种方式
- instanceof右侧要求是一个构造函数,ts会将其细化为
- 1.此构造函数的prototype属性的类型,如果它的类型不是any
- 2.构造签名所返回的类型的联合
typeof
---
1. typeof可以判断数据的类型
2. 针对 ( 对象 ) 和 ( 数组 ) 可以 ( 可以获取变量的声明类型 )
3. 对象
interface TestObj {
name: string;
}
const testObj: TestObj = {
name: 'woow_wu7'
}
type TestObj2 = typeof testObj // TestObj2的类型就是 -> TestObj
4. 函数
function go(address: string): string[] {
return [address]
}
type Go = typeof go // Go的类型就是 -> (address: string) => string[]
(6) 类型谓词 is
- 1.什么是 (
类型保护) ?- 要定义一个类型保护,我们只需定义一个函数,(
该函数的返回值) 是一个 (类型谓词 is)
- 要定义一个类型保护,我们只需定义一个函数,(
- 2.类型谓词的语法
parameterName is Type- parameterName必须是来自于当前函数签名里的一个参数名 - 即必须是函数的参数
(7) in
- 2021/08/31更新
- in运算符作用主要有两个
判断对象中是否存在某个key注意包括 ( 自身属性 ) 和 ( 继承属性 )可以用来遍历枚举类型
in
---
type T = 'name' | 'age';
type Obj = {
[k in T]: any
}
// 1. in 用来遍历枚举类型 -> type Obj = { name: any, age: any}
const obj: Obj = {
name: 'woow_wu7',
age: 20
}
console.log('name' in obj)
// 2. in 用来判断 obj 对象中是否存在 name 属性,缺点是不能识别 ( 自身属性 ) 还是 ( 继承属性 )
var obj = {};
'toString' in obj // true,即非自身属性时,继承的属性也会返回true
(8) as - 类型断言
- 类型断言可以用来 ( 手动指定一个值的类型 ),语法是 (
值 as 类型) 或者 (<类型>值) - tsx中不能使用
<类型>值的方式,只能只用值 as 类型的方式 - 类型断言的作用
- 将一个 ( 联合类型 ) 断言为 ( 其中一个类型 )
- 将一个 ( 父类 ) 断言为 ( 更加具体的子类 )
- 将 ( 任何一个类型 ) 断言为 ( any )
- 将 ( any ) 断言为 ( 一个具体的类型 )
- 类型断言的注意点
- 类型断言只能欺骗ts,但是不能避免运行时的错误
(9) const断言 - value as const
as const- 称为const断言,表示使用最窄或具体的类型,如果不选择断言,则可能因为更广的范围而产生一个错误推断
- 特点
- 该表达式中的 ( 字面类型不应被扩展 )
- 对象字面量获取只读属性
- 数组字面量成为只读元组
1 对象只读属性
---
const obj = {name: 'woow_wu7'} as const
obj.name = '' // 无法分配到 "name" ,因为它是只读属性
2. 数组是只读数组
---
const arr = [1,3] as const
arr[1]= 2
// const arr: readonly [1, 3]
// 无法分配到 "1" ,因为它是只读属性
arr.push(1)
// 类型“readonly [1, 3]”上不存在属性“push”
(10) 非空断言 a!
a!将从值域中排除 (null和undefined)
const a: number|undefined = undefined;
const b = a!
// 结果:b的类型就是 number
// 原因:a! 非空断言表示 ( a的非空,b的类型中不再包含null和undefined)
(11) readonly 和 const 的区别
- 两者都不能被修改
- 变量用const,对象的属性用readonly
(12) ( 类型别名type ) 和 ( 接口interface ) 的区别
- type
- type类型别名会给 ( 类型起一个新名字 )
- type可以作用于原始值,联合类型,元组,以及其他任何需要手写的类型,而instance用于对象
- type不会新建一个类型,它创建了一个新的名字来引用那个类型
- type也可以是泛型
- type 和 interface 的区别
interface是新建一个类型,而type不会新建类型,只是给类型取了一个新的名字type可以作用于原始值,联合类型,元组等其他需要手写的类型,而interface用于对象type不能被 extends继承 和 implements实现
(13) 枚举
- 枚举分类:
- ( 数字枚举 ), ( 字符串枚举 ), ( 异构枚举-混合数字和字符串 ), ( const常量枚举 )
- ( 外部枚举 )
- 反向映射
- 数字枚举成员还具有 - ( 反向映射 )
- 其实字符串枚举也可以,不过key和value要一样
enum Good {
name = 1,
age = 3
}
const number = Good.name // 1
const string = Good[number] // 'name' -> 数字枚举的反向映射
解析:
1. 数字枚举成员能 - 反向映射
2.
问题:为什么数字枚举成员能反向映射?
回答:因为 - enum枚举,既可以做为数据,也可以作为类型
扩展:enum 和 class 既可以做类型,也可以做数据
3.
注意区分 ( T[K] 索引访问造作符 )
(14) jsx
- 官网链接
- 值类型:枚举
- 值范围:'preserve' 'react-native' 'react'
- 含义:指定jsx代码生成,这些模式只在代码生成阶段起作用
- 1 preserve => 生成代码中会保留jsx后续的转换操作(比如以后还可以用babel),输出文件带有 .jsx
- 2 react => 生成 React.createElement,在使用前不需要转化了,输出文件带 .js
- 3 react-native => 保留了所有jsx,输出文件扩展名是 .js
- 如何配置:在tsconfig.json文件配置项compilerOptions中通过 ( jsx选项 ) 来指定
- as
-
jsx中的断言使用
as语法,而不是使用<foo>bar语法
-
(15) extends - 继承 - 实现泛型约束
- 如何实现泛型约束?
- 创建一个 (
接口 - 用来描述约束条件) 配合 (extends关键字) 来实现 (泛型约束)
- 创建一个 (
- extends到底是什么?
- 其实
extends就是 (继承) 的关键字,比如 (class,interface) 的继承
- 其实
- 泛型约束 - 即对T的约束要求 - extends
- 在 ( 泛型约束 ) 中使用 ( 类型参数 )
- 被约束后的泛型变量不再代表任意类型,说明泛型约束针对的是泛型的类型变量T
interface Lengthwise {
length: number;
}
// T extends Lengthwise
// 表示将 ( 泛型类型变量T ) 约束为 ( Lengthwise ) 类型,而 Lengthwise 中具有 length 属性
// 其实就是 T 继承了 Lengthwise 接口,就具有了 interface 中的属性
// 所以下面的函数中获取 length 属性不会再报错
function loggingIdentity<T extends Lengthwise>(arg: T): T {
console.log(arg.length); // Now we know it has a .length property, so no more error
return arg;
}
(16) 泛型
- 泛型函数
- 泛型是函数,该函数可以 ( 适用于多个类型 ),所以叫 ( 泛形 )
- 泛型和any的区别: 泛型不会丢失信息
- ( 泛型函数 ) 的使用方式
- 1.传入所有参数,包括类型参数
- 2.( 类型推论 ),根据参数自动确定T类型
- 泛型变量:(
泛型变量) 代表的是 (任意类型) - 泛型类型 - 泛型接口,泛型接口参数
- 泛型函数的类型
let myIdentity: <T>(arg: T) => T = identity;let myIdentity: {<T>(arg: T): T} = identity;
- 可以使用不同的 ( 泛型参数名 )
- 可以创建 (泛型接口,泛型类),但是不能创建 ( 泛型枚举,泛型命令空间 )
- 泛型接口 - ( 泛型参数 ) 还可以作为整个 ( 泛型接口的参数 )
- 泛型函数的类型
function loggingIdentity<T>(arg: T): T {
console.log(arg.length); // Error: T doesn't have .length
return arg;
}
(1)问题:
- 上面 ( 类型变量T ) 表示任意类型,所以取arg.length报错,因为如果T是number,是没有length属性的
(2)如何解决:
- 把 ( 泛型变量T ) 当作 ( 类型 ) 的一部分使用,比如 ( T[] ),从而增加灵活性
- 具体例子如下
(3) 解决办法1
function loggingIdentity<T>(arg: T[]): T[] {
console.log(arg.length); // Array has a .length, so no more error
return arg;
}
(4) 解决办法2 - 泛型约束
interface Lengthwise {
length: number;
}
function loggingIdentity<T extends Lengthwise>(arg: T): T {
// !!!!!! ------- 通过 extends 来约束T的具体属性 ------- !!!!!!
// !!!!!! ------- 通过 extends 来约束T的具体属性 ------- !!!!!!
// !!!!!! ------- 通过 extends 来约束T的具体属性 ------- !!!!!!
console.log(arg.length); // 泛型约束后,T就具有了length属性,所以可以访问
return arg;
}
(17) 声明合并
- 接口合并
- 把双方的成员,放到一个 ( 同名的接口 ) 中
- 非函数成员
接口的非函数成员应该是唯一的,如果不唯一,那么相同key对于的类型必须一样,不一样会报错
- 函数成员
同名函数会被当作函数重载后面的接口具有更高的优先级,特例是函数的参数是单一的字符串的情况
接口声明合并 - 非函数成员
---
interface Box {
height: number;
width: number;
}
interface Box {
scale: number;
// width: string;
// 1. 接口非函数成员应该唯一,但这里有两个width则不唯一
// 2. 接口非函数成员如果不唯一,则类型必须一样
// 3. 但这里,两个非函数成员width的类型不一致,报错
// 4. 如果这里是 width: number; 则不会报错
}
let box: Box = {height: 5, width: 6, scale: 10};
接口声明合并 - 函数成员
---
interface Cloner { clone(animal: Animal): Animal; }
interface Cloner { clone(animal: Sheep): Sheep; }
interface Cloner {
clone(animal: Dog): Dog;
clone(animal: Cat): Cat;
}
接口声明合并后
interface Cloner {
clone(animal: Dog): Dog;
clone(animal: Cat): Cat;
clone(animal: Sheep): Sheep;
clone(animal: Animal): Animal;
}
// 注意接口中函数属性的顺序,对比声明合并前各接口的顺序
2023-12-18 更新
(18) 泛型工具类型
// 泛型 - 工具类型
// - 详见: 本项目/2-FRONTEND/2-TS/_README.md/ # (二) 范型工具类型
type Color1 = "red" | "yellow";
interface Color2 {
red: string;
yellow: string;
}
enum color3 { // 枚举可以作为 ( 类型 ),也可以作为 ( 值 )
one = 1,
two,
three
}
type color4 = [number, string, symbol]
// 1
// Record
// - 用于将 ( 一种类型属性 - 最终是联合类型 ) 映射到 ( 另一种类型 )
// - Record 的实现详见: 本项目/2-FRONTEND/2-TS/_README.md
// -- keyof 是 索引类型查询 操作符, 返回 T 上已知的公共属性名的 联合类型
// -- T[K] 是 索引访问 操作符,Color2["red"] = string
type TRecord1 = Record<Color1, boolean>; // 鼠标 hover 查看具体的类型
type TRecord2 = Record<keyof Color2, boolean>;
type TRecord3 = Record<keyof Color2, Color2["red"]>;
type TRecord4 = Record<Color1, Color2>;
type TRecord5 = Record<string, any>; // key是string类型,value是any类型
type TRecord6 = Record<keyof any, any>; // key是string | number | symbol,value是any类型
// --- 分割线 ---
type TRecord7 = Record<keyof typeof color3, string> // 相当于 type TRecord7 = { one: string; two: string; three: string; }
type TRecord8 = Record<`${color3}`, string> // 相当于 type TRecord8 = { 1: string; 2: string; 3: string; }
// --- 分割线 ---
type TRecord9 = Record<color4[number], string> // 相当于 type TRecord9 = { [x: string]: string; [x: number]: string; [x: symbol]: string; }
// --- 分割线 ---
const record1: TRecord1 = {
red: true,
yellow: true,
};
const record2: TRecord2 = {
red: true,
yellow: true,
};
const record3: TRecord3 = {
red: "",
yellow: "",
};
const record4: TRecord4 = {
red: {
red: "",
yellow: "",
},
yellow: {
red: "",
yellow: "",
},
};
const record5: TRecord5 = {
name: "woow_wu7",
age: 20,
};
const record6: TRecord6 = {
// key是string | number | symbol,value是any类型
name: "woow_wu7",
age: 20,
10: "number",
};
// 2
// Partial
// - 将 ( 类型 ) 定义的 ( 所有属性 ) 都修改为 ( 可选的 )
type TPartial1 = Partial<Color2>;
type TPartial2 = Partial<Record<"a" | "b", boolean>>;
const partial1: TPartial1 = {
red: undefined, // red可以是 string 或 undefined
// yellow: "", 可选了,即可以没有 yellow 和 red 属性
};
const partial2: TPartial2 = {
// a: true,
// b: false,
// c: true, // a 和 b 属性可选,但是不能超过a和b的范围,即一个新属性 c 就会报错
};
// 3
// Required
interface Color {
a?: number;
b?: string;
c: string;
}
type TR = Required<Color>
const tr: TR = {
a: 1,
b: '2',
c: '3'
}
// 4
// Pick
// - 从类型定义的属性中,选取 ( 指定一组的属性 ),返回一个 ( 新的类型定义 )
// - 从字面意思也能知道是 ( 摘取部分属性 )
// - 注意区分 Pick 和 Omit 和 Exclude 的区别
// ------------------------------------------------------------- Pick 和 Omit 刚好相反
type TPick1 = Pick<Color2, "red">;
type TPick2 = Pick<Color2, "red" | "yellow">;
type TPick3 = Pick<Record<"a" | "b", number>, "b">;
type TPick4 = Pick<Record<"a" | "b" | "c", string>, "a" | "c">;
type TPick5 = Pick<Record<keyof Color2, number>, "red">;
const pick1: TPick1 = {
red: "", // 从 Color2 中选取 red 属性
// yellow: ''// 报错,不能将类型“{ red: string; yellow: string; }”分配给类型“Pick<Color2, "red">”。对象字面量只能指定已知属性,并且“yellow”不在类型“Pick<Color2, "red">”中
};
const pick2: TPick2 = {
red: "", // 从 Color2 中选取 red 和 yellow 属性
yellow: "",
};
const pick3: TPick3 = {
b: 1,
};
const pick4: TPick4 = {
a: "",
c: "",
};
const pick5: TPick5 = {
red: 1,
};
// 5
// Omit
// - 忽略某个属性
// - 注意区分 Pick 和 Omit 和 Exclude 的区别
// ------------------------------------------------------------- Pick 和 Omit 刚好相反
type TOmit1 = Omit<Color2, "red">;
type TOmit2 = Omit<Record<"a" | "b" | "c", boolean>, "a" | "b">;
const omit1: TOmit1 = {
// 忽略 red 属性,则只剩下 yellow 属性
yellow: "",
};
const omit2: TOmit2 = {
c: true,
};
// 6
// Exclude
// - Exclude 就是将前面类型的与后面类型对比,( 过滤出前面独有的属性 )
// - 注意区分 Pick 和 Omit 和 Exclude 的区别
const exclude1: Exclude<"a" | "1" | "2", "a" | "y" | "z"> = "1"; // str 的类型是 "1" | "2",即从前面中去除后面中有的属性
// 7
// ReadOnly
// - 将类型 T 中包含的属性设置为readonly,并返回一个新类型
const readonly1: Readonly<Color2> = {
red: "",
yellow: "",
};
readonly1.red = "11"; // 不能修改,只读,这里报错
// 扩展
// 除了使用 Readonly<Color2>能做到只读外,也可以直接设置 interface Color2 { readonly red: string; }
// 8
// ReadonlyArray
// 8.1
type TReadonlyArray = ReadonlyArray<any>;
const readonlyArr: TReadonlyArray = ["1", 1];
readonlyArr[0] = "11"; // 报错,类型“TReadonlyArray”中的索引签名仅允许读取。
// 8.2
// 在React的useEffect函数签名中
// function useEffect(effect: EffectCallback, deps?: DependencyList): void
// - type EffectCallback = () => (void | (() => void | undefined))
// - type DependencyList = ReadonlyArray<any>
// 7.3
function foo1(arr: ReadonlyArray<string>) {
arr.slice(); // okay
arr.push("hello!"); // error!,只读
}
// 在最新的 typescript3.4 版本中可以使用下面的写法
function foo2(arr: readonly string[]) {
arr.slice(); // okay
arr.push("hello!"); // error! 只读
}
function foo3(arr: readonly string) {
// 报错,仅允许对数组和元组字面量类型使用 "readonly" 类型修饰符。ts(1354)
}
// 9
// Parameters
function fn8(arg: { a: number; b: string }): void {}
type TP1 = Parameters<typeof fn8>;
// 相当于
// type TP1 = [
// arg: {
// a: number;
// b: string;
// }
// ];
// 9
// ReturnType
function fn9(s: string) {
return { a: 1, b: s };
}
type T14 = ReturnType<typeof fn9>; // { a: number, b: string }
type T10 = ReturnType<() => string>; // string -- 这里传入的是 函数签名,即传入是 函数的类型
type T2 = ReturnType<(s: string) => number[]>; // number[]
type T11 = ReturnType<(s: string) => void>; // void
type T12 = ReturnType<<T>() => T>; // {}
type T13 = ReturnType<<T extends U, U extends number[]>() => T>; // number[]
type T15 = ReturnType<any>; // any
type T16 = ReturnType<never>; // any
type T17 = ReturnType<string>; // Error
type T18 = ReturnType<Function>; // Error
// 10
// Uppercase
// Lowercase
type Name = "woow_wu7";
type UpperName = Uppercase<Name>; // 相当于 type UpperName = "WOOW_WU7"
// 11
// InstanceType
class Fn1 {}
type TInstance = InstanceType<typeof Fn1>; // 相当于 type TInstance = Fn
type TInstance2 = InstanceType<any>; // any
type TInstance3 = InstanceType<never>; // any
type TInstance4 = InstanceType<string>; // Error
type TInstance5 = InstanceType<Function>; // Error
// 12
// Awaited
type AAA1 = Awaited<Promise<string>>; // string
type AAA2 = Awaited<Promise<Promise<number>>>; // number - 不管嵌套有多深,都可以得到参数类型
type AAA3 = Awaited<boolean | Promise<number>>; // number | boolean
(二) tsconfig.json
(2.0) tsconfig.json - 顶层属性
compilerOptions ----> 编译选项
extends ------------> 引入其他配置文件,继承配置
exclude ------------> 编译器需要排除的文件,或文件夹
include ------------> 编译器需要编译的文件,或文件夹
typeAcquisition
子属性如下
- enable: boolean是否开启自动引入库类型定义文件.d.ts
- include: array允许自动引入的库名
- exclude: array排除的库名
// acquisition 是收购,获取的意思
files -> 表示编译器需要编译的单个文件列表
references -> 指定依赖工程
compileOnSave -> 可以让IDE在保存文件的时候根据`tsconfig.json`重新生成文件
(2.1) 如何生成 tsconfig.json 文件
tsc --init会生成一个具有默认配置的tsconfig.json文件- 如果一个目录下存在
tsconfig.json文件,那么意味着这个目录是typescript项目的根目录 - tsconfig.json文件中指定了用来编译这个项目的 ( 根文件 ) 和 ( 编译选项 )
(2.2) tsconfig.json 配置项
- 1.如果在
tsconfig.json中,只写一个{},则ts会编译所有此目录和子目录中的.ts文件 - 2.匹配
**/*表示匹配所有 (文件夹) 和 (文件)folder/**/*表示匹配folder中的所有文件夹和文件
compilerOptions
target
// target
// 含义:将ts编译成什么版本的js文件
// 可选值:"ES3", "ES5", "ES6"/ "ES2015", "ES2016", "ES2017","ESNext"
// 默认值:"ES3"
// "ESNext" 表示tc39最新的ES proposed features
module
// module
// 含义:将ts编译成js文件时,js文件使用什么(模块系统)
// 可选值:"None", "CommonJS", "AMD", "System", "UMD", "ES6", "ES2015","ESNext"
// 默认值根据 --target或者target 选项不同而不
// - target=es6时,module=es6
// - target不是es6时,module=commonjs
// - 比如:
// - module=es6时,打包后的js文件中,使用import
// - module=commonjs时,打包后的js文件中,使用require
lib
// lib
// 含义:编译过程中需要引入的 ( 库文件 ) 的列表
// 值类型:string[],
// 默认值:
// - 默认值是根据--target选项不同而不同
// - target=es5时 -> 默认值是 ['DOM', 'ES5', 'ScriptHost']
// - target=es6时 -> 默认值是 ['DOM', 'ES6', 'ScriptHost', 'DOM.Iterable']
// 可选值:可选的值有很多,常用的有ES5,ES6,ESNext,DOM,DOM.Iterable、WebWorker、ScriptHost等
allowJs
checkJs
// 1
// allowJs
// 值类型:boolean ,默认值是false
// 含义:是否允许编译javascript文件,true则表示js后缀的文件也会被typescrpt编辑器编译
// 例子
// allowJs=true,你在ts文件中引入了一个js文件就(不会报错)
// allowJs=flase,你在ts文件文件中引入了一个js文件会(报错)
// 2
// checkJs
// 值类型:boolean,默认值是false
// 含义:是否在 .js 文件中报告错误,与 ( checkJs 和 allowJs ) 一起配合使用
noImplicitAny
// noImplicitAny
// 类型值:boolean,默认是false
// 含义:有 隐含any时是否报错
// 单词:implicit 是隐式的意思
// 例子
// function setName(name) {}
// - 如果 noImplicitAny: false 时,name参数不会报错
// - 如果 noImplicitAny: true 时,name参数会报错,因为name推测出any类型
noUnusedLocals + noUnusedParameters
// 1
// noUnusedLocals
// 类型值:boolean,默认值是false
// 含义:有未使用的 ( 局部 ) 变量时,是否报错
// 注意点:注意这里是局部变量,如果一个变量是非局部变量,比如导出的模块变量 export const a = 1,即使没用到也不会报错!!!!!
// 2
// noUnusedParameters
// 类型值:boolean,默认值是false
// 含义:有未使用的参数时,是否报错
// 例子
// function notUse(age: number, who: string) { // 当设置 noUnusedParameters: true 时,who报错,因为参数未使用
// console.log(`age`, age)
// }
baseUrl
// baseUrl
// 含义:用于解析(非相对模块名称)的(基目录),也可以认为是指定(根目录)
// 配合:baseUrl + paths 可以实现类似alias的功能
// 原因:当配置了 paths 时,一定需要配置 baseUrl
paths
// paths
// 值类型:Object
// 含义:( 模块名 ) 或 ( 路径映射 ) 的列表,类似于alias
// 特点:需要搭配 ( baseUrl )
// 例子1
// "baseUrl": "./",
// "paths": { "@/*": ["src/*"] }
// 例子2
// "baseUrl": "./",
// "paths": {
// "*": ["types/*"]
// },
// "esModuleInterop": true,
// 例子2表示:寻在声明文件需要到 当前目录/types目录中去寻找
// -- 例子3 -- 下面三种写法等价
// "baseUrl": "src", //
// "paths": {
// "@/*": ["/*"]
// }
// "baseUrl": ".",
// "paths": {
// "@/*": ["src/*"]
// }
// "baseUrl": "./src",
// "paths": {
// "@/*": ["/*"]
// }
// -- 例子4 -- 官网的配置
- 遇到问题
- 问题:当在webpack配置了别名后,ts报错找不到模块
- 回答:
- **paths**:因为webpack知道了别名路径,但是ts并不知道这是设置了别名,所以需要设置tsconfig.json文件中的 `paths`
- **baseUrl**: 当设置了 paths时,就必须设置baseUrl
{
"compilerOptions": {
"baseUrl": ".", // this must be specified if "paths" is specified.当指定paths的时候,就必须指定baseUrl
"paths": {
"jquery": ["node_modules/jquery/dist/jquery"] // this mapping is relative to "baseUrl" 该映射是相对于 baseUrl 的
"@/*": "src/*"
}
}
}
官网说明:https://www.typescriptlang.org/tsconfig#paths
esModuleInterop
// esModuleInterop
// 含义:`esModuleInterop`选项的作用是支持使用`import d from 'cjs'`的方式引入`commonjs`包
// 解释:本来 commmonjs只支持require的方法,esModuleInterop=true,则可以使用import的方式
// interop是相互操作的意思
typeRoots
types
// typeRoots 和 types
// 值类型:两者都是array
// - typeRoots数组成员是(@types包的文件夹路径)
// - types数组成员是(npm包名)
// 场景:默认所有可见的 @types包 会在编译过程中被包含进来
// - typeRoots场景:如果指定了typeRoots,则只有typeRoots数组(指定的文件夹)中的(@types包会被包含进来)
// - types场景:如果指定了types,则只有types数组中的(npm包会包含进来)
// 案例
// "typeRoots": ["./typings"], // 只有typings文件夹下的@types包会包含进来,node_modules中的则不会包含进来
// "types": ["jquery"], // jquery库npm包会包含进来
// 官网说明
// - https://www.tslang.cn/docs/handbook/tsconfig-json.html#types-typeroots-and-types
jsx
// jsx
// 值类型:枚举
// 值范围:'preserve' 'react-native' 'react'
// 含义:指定jsx代码生成,这些模式只在代码生成阶段起作用
// 1 preserve => 生成代码中会保留jsx后续的转换操作(比如以后还可以用babel),输出文件带有 .jsx
// 2 react => 生成 React.createElement,在使用前不需要转化了,输出文件带 .js
// 3 react-native => 保留了所有jsx,输出文件扩展名是 .js
模式 | 输入 | 输出 | 输出文件扩展名 |
| -------------- | --------- | ---------------------------- | ------- |
| `preserve` | `<div />` | `<div />` | `.jsx` |
| `react` | `<div />` | `React.createElement("div")` | `.js` |
| `react-native` | `<div />` | `<div />` | `.js` |
outDir // 输出文件夹
rootDir // 输入文件夹
moduleResolution
// moduleResolution
// 值类型:string类型的枚举,支持 ( node ) ( classic )
// 含义:如何处理模块
// 大白话:遇到 import {} from ... 时应该如何去寻找模块
// 一般情况下都选择 node
// moduleResolution: 'node'
removeComments // ------------- boolean,是否移除代码中的注释 !
strictNullChecks // ----------- boolean,是否开启null和undefined检查 !
allowSyntheticDefaultImports // boolean,是否允许从没有设置默认导出的模块中默认导入 !
strict // --------------------- boolean,是否启用 ( 所有 ) 严格类型检查选项,相当于启用 noImplicitAny noImplicitThis alwaysStrict strictNullChecks strictFunctionTypes strictPropertyInitialization !
importHelpers // -------------- boolean,是否从 ( tslib ) 导入辅助工具函数,比如 _extends _rest 等 !
sourceMap // ------------------ boolean,是否生成目标文件的sourceMap文件
skipLibCheck // --------------- boolean,是否跳过lib库检查
noImplicitReturns // ---------- boolean,是否在函数的每个分支都有返回值
---- 分割线 ----
include
exclude
// include 和 exclude
// 值类型:Array
// 含义
// - 在未设置include时,编译器默认包含(当前目录和子目录)的所有typescript文件(.ts, .d.ts 和 .tsx)
// - 当(allowJs=true)时,还包括所有的js文件(.js和.jsx)
// 例子
// "include": ["src/**/*"] // 表示编译src/二级目录/三级目录中的所有(三级目录)中的typescript文件
---- 分割线 ----
2022年1月20更新
----
1
resolveJsonModule
- 表示从 .json 文件中导入,导出其类型
// settings.json ---> { "dry": false, "debug": false }
// import settings from "./settings.json";
// settings.debug === true; // OK
// settings.dry === 2; // Error: '===' 不能用于比较 boolean 和 number 类型
2
isolatedModules
- 是否将每个文件作为单独的模块,默认为true
- 不可以和declaration同时设定
// isolated 表示单独,分离,隔离
3
noEmit
- 不编译输出文件
- 用ts新建一个项目,发现build时,没有输出,最后发现时tsconfig.json中noEmit选项的原因
4
skipLibCheck
- 是否跳过lib库检查,即跳过声明文件的类型检查
- 如果我们开启了这个选项,则可以节省编译期的时间,但可能会牺牲类型系统的准确性。在设置该选项时,推荐值为true
- 具体的tsconfig.json配置说明
{
"compilerOptions": {
/* 基本选项 */
"target": "es5", // 指定 ECMAScript 目标版本: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', or 'ESNEXT'("ESNext"表示最新的ES语法,包括还处在stage X阶段)
"module": "commonjs", // 指定使用模块: 'commonjs', 'amd', 'system', 'umd' or 'es2015'
"lib": [], // 指定要包含在编译中的库文件
"allowJs": true, // 允许编译 javascript 文件
"checkJs": true, // 报告 javascript 文件中的错误
"jsx": "preserve", // 指定 jsx 代码的生成: 'preserve', 'react-native', or 'react'
"declaration": true, // 生成相应的 '.d.ts' 文件
"sourceMap": true, // 生成相应的 '.map' 文件
"outFile": "./", // 将输出文件合并为一个文件
"outDir": "./", // 指定输出目录
"rootDir": "./", // 用来控制输出目录结构 --outDir.
"removeComments": true, // 删除编译后的所有的注释
"noEmit": true, // 不生成输出文件
"importHelpers": true, // 从 tslib 导入辅助工具函数
"isolatedModules": true, // 将每个文件做为单独的模块 (与 'ts.transpileModule' 类似).
/* 严格的类型检查选项 */
"strict": true, // 启用所有严格类型检查选项
"noImplicitAny": true, // 在表达式和声明上有隐含的 any类型时报错
"strictNullChecks": true, // 启用严格的 null 检查
"noImplicitThis": true, // 当 this 表达式值为 any 类型的时候,生成一个错误
"alwaysStrict": true, // 以严格模式检查每个模块,并在每个文件里加入 'use strict'
/* 额外的检查 */
"noUnusedLocals": true, // 有未使用的变量时,抛出错误
"noUnusedParameters": true, // 有未使用的参数时,抛出错误
"noImplicitReturns": true, // 并不是所有函数里的代码都有返回值时,抛出错误
"noFallthroughCasesInSwitch": true, // 报告 switch 语句的 fallthrough 错误。(即,不允许 switch 的 case 语句贯穿)
/* 模块解析选项 */
"moduleResolution": "node", // 选择模块解析策略: 'node' (Node.js) or 'classic' (TypeScript pre-1.6)。默认是classic
"baseUrl": "./", // 用于解析非相对模块名称的基目录
"paths": {}, // 模块名到基于 baseUrl 的路径映射的列表
"rootDirs": [], // 根文件夹列表,其组合内容表示项目运行时的结构内容
"typeRoots": [], // 包含类型声明的文件列表
"types": [], // 需要包含的类型声明文件名列表
"allowSyntheticDefaultImports": true, // 允许从没有设置默认导出的模块中默认导入。
/* Source Map Options */
"sourceRoot": "./", // 指定调试器应该找到 TypeScript 文件而不是源文件的位置
"mapRoot": "./", // 指定调试器应该找到映射文件而不是生成文件的位置
"inlineSourceMap": true, // 生成单个 soucemaps 文件,而不是将 sourcemaps 生成不同的文件
"inlineSources": true, // 将代码与 sourcemaps 生成到一个文件中,要求同时设置了 --inlineSourceMap 或 --sourceMap 属性
/* 其他选项 */
"experimentalDecorators": true, // 启用装饰器
"emitDecoratorMetadata": true, // 为装饰器提供元数据的支持
"strictFunctionTypes": false // 禁用函数参数双向协变检查。
},
/* 指定编译文件或排除指定编译文件 */
"include": [
"src/**/*"
],
"exclude": [
"node_modules",
"**/*.spec.ts"
],
"files": [
"core.ts",
"sys.ts"
],
// 从另一个配置文件里继承配置
"extends": "./config/base",
// 让IDE在保存文件的时候根据tsconfig.json重新生成文件
"compileOnSave": true // 支持这个特性需要Visual Studio 2015, TypeScript1.8.4以上并且安装atom-typescript插件
}
(三) 声明文件 ( .d.ts )
(3.1) 声明文件总结
- 库的分类
- 库分为 ( 全局库 ) 和 ( 模块化库 )
- 什么是
UMD模块- UMD模块指的是:既可以作为模块使用,又可以作为全局模块使用的库
- 声明文件中可以是(
值,或类型)- interface type 对应类型
- let const var function namespace 对应值
class enum 可以是值,也可以是类型
(3.2) 如何编写一个 - ( 全局声明文件 )
- 除了
interface和type,其他全局类型都需要通过declare来声明 namespace相当于就是一个 ( 对象 ),namespace可以嵌套- 如果有两个
同名的interface,则会 ( 声明合并 )
1. 全局变量
declare var foo: number;
declare let foo: number;
declare const foo: number;
2. 全局函数
declare function greet(greeting: string): void;
3. 函数重载
- 说明:`getWidget`函数接收一个数字,返回一个组件,或接收一个字符串并返回一个组件数组
- 声明:
declare function getWidget(n: number): Widget;
declare function getWidget(s: string): Widget[];
4. 接口
如果有两个同名的interface,则会声明合并
interface GreetingSettings {
greeting: string;
duration?: number;
}
5. 别名
type GreetingLike = string | (() => string)
6. 命名空间 ( 相当于一个对象 ),( 注意这里是对象,而不是对象的类型,对象的类型可以用interface来声明 )
declare namespace GreetingLib {
interface LogOptions {
verbose?: boolean;
}
interface AlertOptions {
modal: boolean;
}
}
7. 类 ( 声明的类 - 既是数据也是类型 )
( 即可以是值也可以是类型的,除了class类,还有enum枚举 )
declare class Greeter {
constructor(greeting: string);
greeting: string;
}
(3.3) 如何编写一个 - ( 模块声明文件 )
- 1.模块化库需要修改tsconfig.json文件中的
baseUrl和path以及 ``
{
"compilerOptions": {
"baseUrl": "./",
"paths": {
"*": ["types/*"]
},
"esModuleInterop": true,
// `esModuleInterop`选项的作用是支持使用`import d from 'cjs'`的方式引入`commonjs`包
}
}
表示声明文件要去:当前文件夹下的,types文件夹中寻在
- 2.模块声明和全局声明基本一样,只是模块是import和export的,所以使用需要import,而声明需要export
- 3.当然模块的类型不止是esmodule,其他的模块类型遵循相应模块的与法规则即可
(3.4) 声明文件的规范
这里只记录一些平时不怎么注意的点
- 不要在 ( 回调函数中 ) 使用 ( 可选参数 ),因为大多数情况回调函数的参数都是确定的,除非真的有可选的情况
- 不要因为 ( 回调函数参数个数不同 ) 而写 ( 不同的重载 )
/* 错误 */
declare function beforeAll(action: () => void, timeout?: number): void;
declare function beforeAll(action: (done: DoneFn) => void, timeout?: number): void;
*应该*只使用最大参数个数写一个重载:
/* OK */
declare function beforeAll(action: (done: DoneFn) => void, timeout?: number): void;
(四) React中使用 TS 注意点
1
React.BaseSyntheticEvent
----
const a = (e: React.BaseSyntheticEvent) => {
const html = e?.target?.innerHTML;
// 这里需要使用到 innerHtml 属性,所以不能是 React.MouseEvent<HTMLDivElement>
// React.BaseSyntheticEvent 是react合成事件
// synthetic 是合成的的意思,adj
};
2. 泛型函数的两种写法
- function a<T>(params: T) { .... }
- const a = <T>(params: T) => { .... }
3. ref
3.1
const inputWrapRef: React.MutableRefObject<HTMLLIElement> = useRef<HTMLLIElement>();
3.2
interface InputComponentProps {
inputRef: React.MutableRefObject<Input>;
value: string;
onChange: (e: React.ChangeEvent<HTMLInputElement>) => void;
onKeyDown: (e: React.KeyboardEvent<HTMLInputElement>) => void;
inputWrapRef: React.MutableRefObject<HTMLLIElement>;
}
3.3
const inputValueRef = useRef<string>()
注意:这里ref如果是绑定的input的值,则应该是string类型
4. event
4.1 const onChange = (e: React.ChangeEvent<HTMLInputElement>) => {}
4.2 const onClick = (e: React.MouseEvent<HTMLInputElement>) => {}
4.3 其他事件(e: React.xxEvent <ReactNode>)
4.4
interface TagComponentProps {
onClose: (e: React.MouseEvent<HTMLElement, MouseEvent>) => void;
}
(五) 2022-02-03 更新
(1)
import type
- import type 用来指明 仅仅导入/导出声明
- 解决以下问题:
- import { MyThing } from './some-module.js';
- 这个到底是导入的值,还是类型;!!! 如果是类型在编译成js的时候是会被删除的
资料
- tsconfig.json全解析 lq782655835.github.io/blogs/proje…
- tsconfig.json配置项官网说明 www.tslang.cn/docs/handbo…
- 类型谓词 is 的注意点 segmentfault.com/a/119000002…
- ts基础 juejin.cn/post/699944…
- 常用类型 juejin.cn/post/684490…
- 非空断言操作符