TypeScript学习笔记
1、运行环境(webpack)
1.1、初始化
npm init -y
npm i -D webpack webpack-cli webpack-dev-server html-webpack-plugin typescript ts-loader
1.2、webpack.config.js
const path = require('path')
const htmlWebpackPlugin = require("html-webpack-plugin")
module.exports = {
// 指定文件入口
entry: path.resolve(__dirname, './src/index.ts'),
// 指定打包文件目录
output: {
// 指定打包文件目录
path: path.resolve(__dirname, './dist'),
// 指定打包文件名称
filename: 'bundle.js',
},
// 开启source-map,方便调试
devtool: "inline-source-map",
// require时可以省略对应的后缀名,如有同名文件,会依次匹配
resolve: {
extensions: [".ts", ".js"]
},
// 指定打包时要使用得模块
module: {
// 指定打包规则
rules: [
{
// 目标文件
test: /\.ts$/,
//要使用的loader
use: {
loader: "ts-loader"
},
//要排除的文件夹
exclude: /node_modules/
}
]
},
plugins: [
// 自定义html打包插件
new htmlWebpackPlugin({
// 模板文件
template: "./src/index.html",
// 输出文件
filename: "index.html",
})
],
// 本地开发服务器配置
devServer: {
// 文件路径
static: './dist',
// 第一次构建是否自动用浏览器打开网页
open: true,
// 端口
port: 9000
},
// 模式development|production
mode: 'development',
// 指定Webpack构建的环境为web
target: "web"
}
1.3、tsconfig.json
{
// 编译选项
"compilerOptions": {
// 目标语言的版本
"target": "ES6",
// 生成代码的模板标准
"module": "ES6",
// 开启所有严格的类型检查
"strict": true
}
}
1.4、index.ts
alert("hello world in typescript!")
1.5、index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
Hello World!
<script type="text/javascript" src="../dist/bundle.js" charset="utf-8"></script>
</body>
</html>
1.6、package.json
{
"name": "typescript",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"dev": "webpack-dev-server --open",
"build": "webpack --mode production"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"html-webpack-plugin": "^5.5.3",
"ts-loader": "^9.4.4",
"typescript": "^5.1.6",
"webpack": "^5.88.1",
"webpack-cli": "^5.1.4",
"webpack-dev-server": "^4.15.1"
}
}
1.7、测试
2、数据类型
ts类型是在开发的时候检测,编译后不存在类型,ts具有类型推导能力,只有在无法推断或需明确指定才需显式声明类型
- any、unknow
- Object
- Number、String、Boolean(包装类)
- number、string、boolean
- 1、‘xumeng03’、true(字面量类型)
- never(不存在的值)
2.1、any
不进行类型检测,使用如同Js里的变量
let str1: any = 'xumeng03'
let str2: string;
str2 = str1;
let str3: unknown;
str3 = str1;
2.2、unknow
不认为变量为任意一种类型
let str1: unknown = 'xumeng03'
let str2: string;
// 报错
// str2 = str1;
let str3: any;
str3 = str1;
2.3、基础类型
1、number
可以用来表示整数和分数
属性 | 描述 |
---|---|
MAX_VALUE | 最大值 |
MIN_VALUE | 最小值 |
POSITIVE_INFINITY | 正无穷大 |
NEGATIVE_INFINITY | 负无穷大 |
方法 | 示例 | 描述 |
---|---|---|
toString() | 把数字转换为字符串,使用本地数字格式顺序 | |
valueOf() | 返回一个 Number 对象的原始数字值 | |
toPrecision() | num.toPrecision(1) | 把数字格式化为指定的长度(小数点不算) |
toFixed() | toFixed(1) | 把数字转换为字符串,并指定位小数点位数 |
// 数字类型
let age: number = 22;
console.log("数字类型", age);
2、string
''和""可以表示常规字符串,``可以表示插值字符串
属性 | 描述 |
---|---|
length | 字符串的长度 |
方法 | 描述 |
---|---|
charAt() | 指定位置的字符 |
charCodeAt() | 指定的位置的字符的 Unicode 编码 |
concat() | 连接两个或更多字符串,返回新的字符串 |
indexOf() | 指定的字符串值在字符串中首次出现的位置 |
lastIndexOf() | 指定的字符串值在字符串中反向第一次出现的位置 |
localeCompare() | 用本地特定的顺序来比较两个字符串;大于0当前字符串大;等于0字符串一样大;小于0当前字符串小 |
match() | 查找找到一个或多个正则表达式的匹配 |
replace() | 替换与正则表达式匹配的子串 |
search() | 检索与正则表达式相匹配的值 |
split() | 把字符串分割为子字符串数组 |
substr(start, length) | 从起始索引号提取字符串中指定数目的字符 |
substring(start,stop) | 提取字符串中两个指定的索引号之间的字符 |
toLowerCase() | 转小写 |
toUpperCase() | 转大写 |
// 字符串类型
// @ts-ignore
let name: string = "xumeng03";
console.log("字符串类型", name);
let introduce: string = `my name is ${name}, my age is ${age}`;
console.log("字符串类型", introduce);
3、boolean
值为true/false
// 布尔类型
let isStudent: boolean = false
console.log("布尔类型", "是否学生", isStudent);
2.4、包装类型
1、Number
let a1: Number = Number(1)
let a2: number;
//错误
// a2 = a1;
a2 = a1.valueOf();
2、String
let a1: String = String('xumeng03')
let a2: string;
//错误
// a2 = a1;
a2 = a1.valueOf();
3、Boolean
let a1: Boolean = Boolean(true)
let a2: boolean;
//错误
// a2 = a1;
a2 = a1.valueOf();
2.5、引用类型
1、对象
- Object:可以包含所有JS类型,一旦赋值无法进行属性新增
- object:可以包含所有的引用类型(数组类型、对象类型、函数类型)、包装类(Number、String、Boolean),不能包含原始类型
- {}:如同Object
2、接口
interface通常用于描述类、对象;
基础用法
interface IPerson {
// 必选属性
readonly id: number; // 只读属性
name: string;
age: number;
// 可选属性
address?: string;
// 索引签名
[key: string]: any;
}
let zhangsan: IPerson = {
id: 1,
name: "zhangsan",
age: 23,
// 可选属性
address: '中国',
// 索引签名
tag: [1, 2, 3]
}
// 错误,id是只读属性
// zhangsan.id = 2
接口继承(可多继承)
// 接口
interface IPerson {
// 必选属性
id: number;
name: string;
age: number;
}
interface Chinese extends IPerson {
address: string;
}
let zhangsan: Chinese = {
id: 1,
name: "zhangsan",
age: 23,
// 可选属性
address: '中国'
}
接口实现
// 接口
interface IPerson {
// 必选属性
id: number;
name: string;
age: number;
}
class Person implements IPerson {
id: number;
name: string;
age: number;
constructor(id: number, name: string, age: number) {
this.id = id;
this.name = name;
this.age = age;
}
}
3、数组
方法 | 描述 |
---|---|
concat() | 连接两个或更多的数组,并返回结果 |
every() | 检测数值元素的每个元素是否都符合条件 |
filter() | 检测数值元素,并返回符合条件所有元素的数组 |
forEach() | 数组每个元素都执行一次回调函数 |
indexOf() | 搜索数组中的元素,并返回它所在的位置;如果搜索不到,返回-1 |
join() | 把数组的所有元素放入一个字符串 |
lastIndexOf() | 返回一个指定的字符串值最后出现的位置 |
map() | 通过指定函数处理数组的每个元素,并返回处理后的数组 |
pop() | 删除数组的最后一个元素并返回删除的元素 |
push() | 向数组的末尾添加一个或更多元素,并返回新的长度 |
reduce() | 将数组元素计算为一个值(从左到右) |
reverse() | 反转数组的元素顺序返回一个字符串 |
shift() | 删除数组并返回数组的第一个元素 |
unshift() | 向数组的开头添加一个或更新元素,并返回新的长度 |
slice(start, stop) | 选取数组的的一部分,并返回一个新数组 |
some() | 检测数组元素中是否有元素符合指定条件 |
sort() | 对数组的元素进行排序 |
splice(start, removeLength, addStr) | 从数组中添加或删除元素 |
toString() | 把数组转换为字符串,并返回结果 |
// 数组类型
let hobby: string[] = ['book', 'code']
// let hobby: Array<string> = ['book', 'code']
console.log("数组类型", hobby);
let code: (string | number)[] = [1, 'java']
console.log("数组类型", code);
// 多维数组
let books: [string[], number[]] = [['book', 'code'], [1, 2]]
// IArguments
function a(...args: any[]) {
let a: IArguments = arguments
console.log(a)
}
a(1,2,2,3,3,3,3,3,3,3,2)
4、元组
// 元组类型
let userinfo: [string, number, boolean] = ['zhangsan', 23, false]
console.log("元组类型", userinfo);
5、函数
// 函数定义
let fun1 = function (a: string, b: string): string {
return a + b;
}
let fun2 = (a: string, b: string): string => {
return a + b;
}
// 可选参数
type Fun3 = (a: string, b: string, c?: string) => string
let fun3: Fun3 = (a, b, c): string => {
return a + b;
}
console.log(fun2('1', '2'));
console.log(fun3('1', '2', '3'));
// 默认值(不可与可选参数一起用)
type Fun4 = (a: string, b: string) => string
let fun4 = (a = 'abc', b: string = 'def'): string => {
return a + b;
}
console.log(fun4());
// 函数重载
function fun5(a: string): string;
function fun5(a: number): number;
function fun5(a: string | number): string | number {
return a;
}
6、枚举
// 枚举,推荐使用常量枚举,不会额外生成对象
enum ROLE {
Student,
Teacher,
ADMIN
}
console.log("枚举类型", ROLE.ADMIN, ROLE[0]);
const enum ROLE1 {
Student,
Teacher,
ADMIN
}
console.log("枚举类型", ROLE1.ADMIN);
const enum ROLE2 {
Student = 1,
Teacher = 5,
ADMIN
}
console.log("枚举类型", ROLE2.ADMIN);
const enum ROLE3 {
Student = 'a',
Teacher = 'b',
ADMIN = 'c'
}
console.log("枚举类型", ROLE3.ADMIN);
console.log("枚举类型", ROLE[0]);
// 数字枚举可以反向映射,字符串枚举不行
// console.log("枚举类型", ROLE3['a']);
7、类
// 类
class Person {
// 实例属性(修饰符public、protected、private)
name: string = 'xumeng';
age: number = 22;
// 实例私有属性
private _id: number = 1
// 实例只读属性
readonly _type: string = '多细胞生物'
get getId() {
return this._id
}
set setId(id: number) {
this._id = id
}
// 静态属性
static type: string = '人类'
// 构造方法
constructor(name: string, age: number, world: (...args: any[]) => any) {
this.name = name
this.age = age
this.world = world
}
// 原型方法
hello() {
return "hello!"
}
// 实例方法
world: () => "";
}
// 实例
let person = new Person("xumeng03", 22, () => "world");
console.log(person, person.getId, Person.type, person.hello(), person.world());
// 继承
class Chinese extends Person {
address: string = '中国';
constructor(name: string, age: number, address: string) {
super(name, age, () => "world")
this.address = address
}
hello() {
return "你好世界!"
}
}
let chinese = new Chinese("xumeng03", 22, '上海')
// 判断对象是否是目标类的实例
console.log(chinese instanceof Person);
8、抽象类
// 抽象类
abstract class Animal {
// 实例属性
abstract name: string;
// 实例方法
abstract eat: () => string;
// 原型方法
abstract speak(): string;
}
class Cat extends Animal {
name: string = 'cat';
constructor() {
super();
this.eat = () => ""
}
eat: () => "";
speak(): string {
return "miao~";
}
}
let cat = new Cat()
console.log(cat);
2.6、联合类型&交叉类型
1、联合类型
两者满足任意一个即可
let strOrNum: string | number='abc';
strOrNum = 1
2、交叉类型
需同时满足两者
class Person1 {
id: number
constructor(id: number) {
this.id = id
}
}
class Person2 {
name: string
constructor(name: string) {
this.name = name
}
}
let person: Person1 & Person2 = {
id: 1,
name: "xumeng03"
}
2.7、内置对象
let date: Date = new Date();
let reg: RegExp = new RegExp(/\w/);
let err: Error = new Error("Error");
let xhr: XMLHttpRequest = new XMLHttpRequest();
let html1: HTMLHtmlElement | null = document.querySelector('html')
let input1: HTMLInputElement | null = document.querySelector('input')
let div1: NodeList = document.querySelectorAll('div')
let div2: NodeListOf<HTMLElement | HTMLDivElement> = document.querySelectorAll('div')
let storage:Storage = localStorage
2.8、特殊类型
1、null、undefined
null表示对象值缺失,undefined表示初始化变量为一个未定义的值,严格模式(默认模式)不可混用
// null类型、undefined类型
let a: null = null
console.log("null类型", a);
let b: undefined = undefined
console.log("undefined类型", b);
2、void
常用于函数的返回值
// void类型
function hello(): void {
alert("hello world");
}
hello()
3、never
是所有类型(包括 null 和 undefined)的子类型,表示从不会出现的值/无终点
type A = 'code' | 'write'
// 新增属性会导致TheType函数报错,可以起到逻辑完整性检测的作用
// type A = 'code' | 'write' | 'read'
function TheType(type: A) {
switch (type) {
case "code":
console.log("code");
break
case "write":
console.log("write");
break
default:
const theType: never = type
break
}
}
4、symbol
let a1: symbol = Symbol(1)
let a2: symbol = Symbol(1)
// Symbol.for会寻找有没有当前key,如果有直接用
console.log(a1, a2, a1 === a2, Symbol.for('xumeng03') === Symbol.for('xumeng03'))
let a = {
id: 1,
[a1]: 1,
[a2]: 2,
}
// 获取所有属性值(string/symbol)
console.log(Reflect.ownKeys(a));
// 生成器(灵活的控制函数的暂停执行)
function* progress() {
yield 33
yield 66
return 99.9
}
const generator = progress()
console.log(generator.next())
console.log(generator.next())
console.log(generator.next())
// 生成器(分段传参)
function* progress1(num: number) {
let result = 0
console.log(num, result)
// 第一个next在此处卡住
result = yield num + result;
console.log(num, result)
// 第二个next在此处卡住,第三个next从此处继续执行
result = yield num + result;
console.log(num, result)
}
const generator1 = progress1(1)
console.log(generator1.next())
console.log(generator1.next(2))
console.log(generator1.next(3))
// 迭代器,可迭代对象(string、array、Set、NodeList、Arguments、Map)
// string
let str = 'xumeng03'
for( let text of str) {
console.log(text) //字符串每个遍历打印
}
// 数组
const bears = ['book', 'code', 'game']
for( let bear of bears) {
console.log(bear)
}
2.8、类型断言
function ilength(str: string | number) {
return (str as string).length;
}
console.log(ilength('abc'));
console.log(ilength(123));
let strOrNum: string | number;
console.log("类型断言", (strOrNum! as string).includes("a"));
console.log("类型断言", (<string>strOrNum!).includes("a"));
2.9、自定义类型
type通常用于描述函数签名、联合类型、工具类型、映射条件类型;
// 自定义类型
type Direction = 'up' | 'down'
let abc: Direction;
abc = 'up'
type s1 = string
type s2 = string | number
type s3 = () => string
2.10、内置工具类型
1、Record
type k = 1 | 2 | 3
interface Student {
name: string;
age: number;
}
const p: Record<number, Student> = {
1: {
name: 'xumeng01',
age: 20
},
2: {
name: 'xumeng02',
age: 20
},
3: {
name: 'xumeng03',
age: 20
},
}
2、Partial
让传入类型中的所有属性变成都是可选的
interface Student {
name: string;
age: number;
}
// 报错,name、age为必选属性
// const student1: Student = {}
const student2: Partial<Student> = {}
3、Required
让传入类型中的所有属性变成都是必选的
interface Student {
name?: string;
age?: number;
}
const student1: Student = {}
// 报错,name、age为必选属性
// const student2: Required<Student> = {}
4、Readonly
让传入类型中的所有属性变成都是只读的
interface Student {
name: string;
age: number;
}
const student1: Student = {
name: 'xumeng02',
age: 20
}
student1.age = 21
const student2: Readonly<Student> = {
name: 'xumeng03',
age: 20
}
// 报错,属性age只读
// student2.age = 21
5、Pick
选择传入类型中的部分属性组成新类型
interface Student {
name: string;
age: number;
}
const student1: Student = {
name: 'xumeng01',
age: 20
}
const student2: Pick<Student, 'name'> = {
name: 'xumeng02'
}
const student3: Pick<Student, 'name'> = {
name: 'xumeng03',
// 报错,Pick<Student, 'name'>没有age属性
// age: 20
}
const student4: Pick<Student, 'name' | 'age'> = {
name: 'xumeng04',
age: 20
}
6、Exclude
针对联合类型,排除相同的,留下不同的
type PersonAttr = 'name' | 'age'
type StudentAttr = 'name' | 'age' | 'class' | 'school'
const student1: Exclude<StudentAttr, PersonAttr> = 'class'
7、Extract
针对联合类型,排除不同的,留下相同的
type PersonAttr = 'name' | 'age'
type StudentAttr = 'name' | 'age' | 'class' | 'school'
const student1: Extract<StudentAttr, PersonAttr> = 'name'
8、Omit
传入一个类型,和这个类型的几个属性,把传入的属性省略掉,组成一个新类型
interface Student {
name: string;
age: number;
class: string;
school: string;
}
export type PersonAttr = 'name' | 'age'
const student1: Omit<Student, PersonAttr> = {
class: '',
school: ''
}
9、NonNullable
不能为空
type k = string | null | undefined
// 报错,不能为空
// let p: NonNullable<k> = null
// 报错,不能为空
// let p: NonNullable<k> = undefined
10、Parameters
获取传入函数的参数组成的元组类型
interface StudentFunc {
(name: string, age: number): string
}
const student1: Parameters<StudentFunc> = ['xumeng03', 22]
11、ConstructorParameters
获取传入构造函数的参数组成的元组类型
class Student {
name: string;
age: number;
}
const student1: ConstructorParameters<new (name: string, age: number) => Student> = ['xumeng03', 22]
12、ReturnType
获取传入函数的返回类型
class Student {
name: string;
age: number;
}
const student1: ReturnType<(name: string, age: number) => Student> = {
name: 'xumeng03',
age: 22
}
13、InstanceType
获取传入构造函数的返回类型
class Student {
name: string;
age: number;
constructor(name: string, age: number) {
this.name = name
this.age = age
}
}
const student1: InstanceType<typeof Student> = {
name: 'xumeng03',
age: 22
}
14、Uppercase
type StudentSexType = 'male' | 'female'
const studentSex: Uppercase<StudentSexType> = 'MALE'
15、Lowercase
type StudentSexType = 'MALE' | 'FEMALE'
const studentSex: Lowercase<StudentSexType> = ''
16、Capitalize
type StudentSexType = 'male' | 'female'
const studentSex: Capitalize<StudentSexType> = ''
17、Uncapitalize
type StudentSexType = 'MALE' | 'FEMALE'
const studentSex: Uncapitalize<StudentSexType> = ''
2.11、infer
1、类型推断
type k<T> = T extends Array<infer U> ? U : T
const a: k<string[]> = 'xumeng03'
2、类型提取
type arr = ['a', 'b', 'c']
type p1<T extends any[]> = T extends [infer U, ...any[]] ? U : [];
type p2<T extends any[]> = T extends [...infer U, infer K] ? U : [];
const b1: p1<arr> = 'a'
const b2: p2<arr> = ['a', 'b']
3、递归
type arr = ['a', 'b', 'c']
type rever<T extends any[]> = T extends [infer f, ...infer rest] ? [...rever<rest>, f] : T;
const a: rever<arr> = ['c', 'b', 'a']
3、泛型
3.1、定义
// 接口中使用泛型
interface fun4<T> {
id: T
}
let data1: fun4<number> = {
id: 1
}
// 方法中使用泛型
const fun2 = function <T>(param: T): T {
return param
}
console.log(fun2<number>(1));
console.log(fun2<string>("xumeng03"));
// type中使用泛型
type IFun = <T>(param: T) => T
const fun3: IFun = (param) => {
return param
}
console.log(fun3<number>(1));
console.log(fun3<string>("xumeng03"));
3.2、泛型默认值
const fun4 = <T = string>(param: T): T => {
return param
}
console.log(fun4("xumeng03"));
3.3、泛型约束
// 泛型约束
const fun5 = function <T extends number>(param1: T, param2: T) {
return param1 + param2;
}
console.log(fun5<number>(1, 1));
// console.log(fun5<string>("xumeng03","22"));
type I1 = {
age: number
}
const fun6 = function <T extends I1>(param: T): number {
return param.age
}
type I2 = {
name: string
age: number
}
const fun7 = function <T extends I2, U extends keyof I2>(param: T, key: U): T[U] {
return param[key]
}
console.log(fun7({name: "xumeng03", age: 23}, "name"));
console.log(fun7({name: "xumeng03", age: 23}, "age"));
type I3<T extends I2, U extends keyof I2> = T[U]
const fun8 = function <T extends I2, U extends keyof I2>(param: T, key: U): I3<T, U> {
return param[key]
}
3.4、泛型抽离
type I3<T extends I2, U extends keyof I2> = T[U]
const fun8 = function <T extends I2, U extends keyof I2>(param: T, key: U): I3<T, U> {
return param[key]
}
3.5、条件分发
type Code<T> = T extends 200 | 201 ? true : false
type icode1 = Code<200>
type icode2 = Code<201>
type Code1<T, U> = T extends U ? true : false
type icode3 = Code1<201, number>
type icode4 = Code1<201, string>
type I4<T> = T extends number ? number : string;
const fun9 = function <T extends number | string>(param1: T, param2: T): I4<T> {
return param1 + (param2 as any);
}
type I5<T> = T extends number ? number : string;
// 涉及到泛型时会进行类型分发(string | number)
type type1 = I5<string | number>
// 直接使用不会进行类型分发(string)
type type2 = (string | number) extends number ? number : string;
避免条件分发
// 避免条件分发
type I6<T> = T & {};
type type3 = I6<string | number> extends number ? number : string;
判断条件分发是否相等
// 判断条件分发是否相等
type I7<T, U> = T extends U ? U extends T ? true : false : false;
type type4 = I7<string, number>
type type5 = I7<string, string>
获取两个类型交集
// 获取两个类型交集
type I8 = Extract<string | number, string>
排除两个类型交集
// 排除两个类型交集
type I9 = Exclude<string | number, string>
判断非空
let e = document.getElementById("app")
type I10 = NonNullable<typeof e>
3.6、类型推断
// 类型推断
function fun1(param1: string, param2: number) {
return {param1, param2}
}
type t1 = typeof fun1;
// type ReturnType<T> = T extends (param1: string, param2: number) => infer R ? R : never;
// type ReturnType<T> = T extends (...args: any) => infer R ? R : never;
type t2 = ReturnType<typeof fun1>;
function fun2(param1: string, param2: number) {
return {param1, param2}
}
type ReturnType1<T extends (...args: any) => any> = T extends (...args: infer R) => any ? R : never;
type t3 = ReturnType1<typeof fun1>;
4、命名空间
在最新的TypeScript版本中,推荐使用ES模块(ES Modules)作为模块化的解决方案,而不是过度使用命名空间
// 命名空间
namespace Zoo {
export let name: string
export class Dog{}
}
console.log(Zoo.name, Zoo.Dog)
namespace Home {
export let name: string
export class Dog{}
}
console.log(Home.name, Home.Dog)
5、tsconfig.json
{
// 编译选项
"compilerOptions": {
// 编译时会生成一个缓存文件,第二次编译会读取缓存文件,加快编译速度
"incremental": true,
// 缓存文件位置
"tsBuildInfoFile": ".tsbuildinfo",
// 打印编译信息
"diagnostics": false,
// 目标语言的版本
"target": "ES6",
// 生成代码的·模板·标准
"module": "ES6",
// ts使用的库
// "lib": [],
// 允许编译js
// "allowJs": false,
// 允许js报错,一般与allowJs一起使用
// "checkJs": false,
// 指定输出目录
"outDir": "./dist",
// 指定文件目录
"rootDir": "./",
// 自动生成声明文件
"declaration": true,
// 指定生成文件位置
"declarationDir": "",
// 生成声明文件的sourcemap
"declarationMap": false,
// 生成目标文件的sourcemap
"sourceMap": false,
"inlineSourceMap": false,
// 第三方声明文件的放置位置
"typeRoots": [],
"types": [],
// 删除注释
"removeComments": true,
// 编译后不产生js文件
"noEmit": false,
// 编译发生错误不会输出js文件
"noEmitOnError": true,
// 遍历器降级
"downlevelIteration": false,
// 开启所有严格的类型检查
"strict": true,
// 严格模式下为文件头部注入"use strict"
"alwaysStrict": true,
// 不允许隐式的any
"noImplicitAny": true,
// 不允许把null、undefined赋值给其他变量
"strictNullChecks": true,
// 不允许函数双向协变
"strictFunctionTypes": false,
// 类的实例属性必须初始化
"strictPropertyInitialization": false,
// 严格检查Bind、Call、Apply类型
"strictBindCallApply": true,
// 不允许this有隐式的any类型
"noImplicitThis": false,
// 检查未使用的局部变量
"noUnusedLocals": false,
// 检查未使用的函数参数
"noUnusedParameters": false,
// 放置switch语句贯穿(没有break)
"noFallthroughCasesInSwitch": false,
// 模块编译策略
"moduleResolution": "classic",
// 解析非相对模块的基地址
"baseUrl": "./",
// js语法的解析器
"jsxFactory": "React.createElement",
// jsx解析器
"jsx": "preserve",
// 路径映射
"paths": {
// 手动指定json5版本
"@json5": [
"node_modules/json5/dist/index.min.js"
]
}
},
// 指定编译目录
"include": [
"src/**/*"
],
// 编译排除目录
"exclude": [],
// 指定文件使用该配置
"files": []
}
6、声明文件
常用于第三方库没有声明文件时时候
declare const xumeng: string;
7、装饰器
tsconfig中compilerOptions的experimentalDecorators需要设置为true
-
装饰器的执行时机,不是在创建实例的时候运行,而是在类创建的时候就会执行
-
装饰器对类的行为的改变,是代码编译时发生的,而不是在运行时。这意味着,装饰器能在编译阶段运行代码
7.1、类装饰器
// 类装饰器
const Xuehua: ClassDecorator = (target) => {
// target代表class Xue
console.log(target);
target.prototype.name = "xumeng03"
target.prototype.helloworld = () => {
return "hello world!"
}
}
@Xuehua
class Xue {
constructor () {
}
// ......
}
const xue = new Xue() as any
console.log(xue.name,xue.helloworld())
7.2、装饰器工厂
// 装饰器工厂
const Fun = (name: string): ClassDecorator => {
return (target) => {
// target代表class Xue
console.log(target);
target.prototype.name = name
target.prototype.helloworld = () => {
return "hello " + name + '!';
}
}
}
@Fun("xumeng03")
class Xue {
constructor() {
}
// ......
}
const xue = new Xue() as any
console.log(xue.name, xue.helloworld())
7.3、多装饰器
// 装饰器工厂
const Fun = (name: string): ClassDecorator => {
return (target) => {
// target代表class Xue
console.log(target);
target.prototype.name = name
target.prototype.helloworld = () => {
console.log("hello " + name + '!')
}
}
}
const Fun2 = (name: string): ClassDecorator => {
return (target) => {
// target代表class Xue
console.log(target);
target.prototype.name1 = name
target.prototype.helloworld1 = () => {
console.log("hello " + name + '!')
}
}
}
// 执行顺序由下到上
@Fun("xumeng03")
@Fun2("xumeng")
class Xue {
constructor() {
}
// ......
}
const xue = new Xue() as any
7.4、函数装饰器
const Fun = (name: string): MethodDecorator => {
return (target, key, descriptor: PropertyDescriptor) => {
// target代表class Xue
console.log(target, key, descriptor, name);
// ......
descriptor.value(name)
}
}
class Xue {
constructor() {
}
@Fun("xumeng03")
getName(data: string): void {
console.log('hello ' + data + '!')
}
}
const xue = new Xue();
7.5、参数装饰器
待补。。。
7.6、属性装饰器
待补。。。
8、逆变&协变&双向协变
// 协变(变量)
class Biology {
id: number
}
class Person extends Biology {
name: string
}
let b: Biology
let p: Person = {
id: 2,
name: "xumeng03"
}
b = p
// 逆变(函数)
let b1 = (param1: Biology) => {
}
let p1 = (param1: Person) => {
}
// 报错
// b1=p1
p1=b1
// 双向协变(tsconfig中compilerOptions的strictFunctionTypes需要设置为false)
let b1 = (param1: Biology) => {
}
let p1 = (param1: Person) => {
}
// 不再报错
b1=p1
p1=b1