实用指南:TypeScript知识总结
一、简介
TypeScript由微软开发,是基于JavaScript的一个扩展语言。TypeScript包含了JavaScript的所有内容,即:TypeScript是JavaScript的超集Typescript增加了:静态类型检查、接口、泛型等很多现代开发特性,因此更适合大型项目的开发TypeScript需要编译为JavaScript,然后交给浏览器或其他JavaScript运行环境执行
二、为什么需要TypeScript?
JavaScript 当年诞生时的定位是浏览器脚本语言,用于在网页中嵌入一些简单的逻辑,而且代码量很少。
随着时间的推移,JavaScript变得越来越流行,如今的 JavaScript 已经可以全栈编程了。
现如今的 JavaScript 应用场景比当年丰富的多,代码量也比当年大很多,随便一个JavaScript 项目的代码量,可以轻松的达到几万行,甚至十几万行!
然而 JavaScript 当年“出生简陋”没考虑到如今的应用场景和代码量,逐渐的就出现了很多困扰
JS的困扰
1.1. 不清不楚的数据类型


1.2. 有漏洞的逻辑
else if{}中的语句永远不会执行,但是js不会报错


1.3. 访问不存在的属性


1.4. 拼写错误


静态类型检查
- 在代码运行前进行检查,发现代码的错误或不合理之处,减小运行时异常的出现的几率,,此种检查叫『静态类型检查』,TypeScript 的核心就是『静态类型检查』,简言之就是把运行时的错误前置(比如同样的错误代码,js只有在运行时才会报错,但是ts在写代码的时候就会报错)。
- 同样的功能,TypeScript的代码量要大于JavaScript,但由于 TypeScript 的代码结构更加清晰,在后期代码的维护中 TypeScript 却远胜于 JavaScript。
TS与JS的区别
| TypeScript | JavaScript |
|---|---|
| JavaScript 的超集用于解决大型项目的代码复杂性 | 一种脚本语言,用于创建动态网页 |
| 可以在编译期间发现并纠正错误 | 作为一种解释型语言,只能在运行时发现错误 |
| 强类型,支持静态和动态类型 | 弱类型,没有静态类型选项 |
| 最终被编译成 JavaScript 代码,使浏览器可以理解 | 可以直接在浏览器中使用 |
| 支持模块、泛型和接口 | 不支持模块,泛型或接口 |
| 社区的支持仍在增长,而且还不是很大 | 大量的社区支持以及大量文档和解决问题的支持 |
三、编译TypeScript
浏览器不能直接运行TypeScript代码,需要编译为Javacript代码
1. 命令行编译(几乎不用)
要把.ts文件编译为.js文件,需要配置TypeScript的编译环境,步骤如下
- 成功创建一个demo.ts文件
const person = {
name: '李四',
age: 18,
}
console.log(`我叫${ person.name },我今年${ person.age }岁了`)
- 安装全局TypeScript
npm i typescript -g
- 使用命令编译.ts文件
tsc demo.ts
2. 自动化编译
- 创建TypeScript编译控制文件:
tsconfig.json
tsc --init
- 监视目录中所有.ts文件的变化
tsc --watch
- 小优化:希望当编译出错时不生成
.js文件
"compilerOptions": {
"noEmitOnError": true,
}
{
// 这个文件是ts编译器的配置文件,ts编译器可以根据他的信息来对代码进行编译
//"include":用来指定哪些ts文件需要被编译
//路径:**表示任意目录
// *表示任意文件
//"exclude”:用来指定哪些文件不需要被编译
//默认值:["node_modules","bower_components","jspm_packages"]
// "include": [
// "src/**/*"
// ],
// "exclude": [
// "node_modules"
// ]
//编译器的选项
"compilerOptions": {
//指定ts被编译为js的版本
"target": "es2015",//ES6
//指定js的模块化规范
"module": "es2015",
//用来指定编译后的文件所放的目录
"outDir": "./dist",
//将代码合并为一个文件,设置outFile后,
// 所有的全局作用域中的代码会合并到同一个文件中
"outFile": "./dist/bundle.js",
//是否对js文件进行编译,默认是false
"allowJs": true,
//是否检查js代码是否符合语法规范,默认是false
"checkJs": true,
//是否移除注释
"removeComments": true,
//不生成编译后的文件
"noEmit": true,
//当有错误时不生成编译后的文件
"noEmitOnError": true,
//设置编译后的js文件是否使用严格模式,默认false
//所有严格检查的开关(设置了这个后后面四个就不用写了)
"strict": true,
"alwaysStrict": true,
//不允许隐式的any类型
"noImplicitAny": true,
//不允许不明确类型的this
"noImplicitThis": true,
//严格检查空值
"strictNullChecks": true,
}
}
四、类型声明
- 类型声明是TS非常重要的一个特点
- 通过类型声明可以指定TS中的变量(参数,形参)的类型
- 指定类型后,当为变量赋值时,TS编译器会自动检查值是否符合类型声明,符合则赋值,否则报错
- 类型声明给变量设置了类型,使得变量者能存储某种类型的值
- 语法:
//声明一个变量,同时指定为Number类型
let a: number;
a = 10;
//下面这行会报错:不能将类型“string”分配给类型“number”。
//但是即使报错也会编译成功(编译成js)
// a="333";
//声明变量的同时进行赋值(会自动进行类型检测)
let c = false;
c = true;
//参数要指定类型,返回值也要指定类型
function test(a: number, b: number) {
return a + b;
}
//可以直接使用字面量进行类型声明
let d: 10;
//报错:不能将类型“11”分配给类型“10”。
// d=11;
//可以使用|来连接多个类型(联合类型)
let e: "male" | "female";
e = "male";
e = "female";
let f: number | string;
f = 10;
f = "10";
五、类型判断
- TS拥有自动类型判断机制
- 当对变量的声明和赋值同时进行时,TS编译器会自动判断变量的类型
let d=-99;//TypeScript会自动推算出d的类型是number
d=false;会报错
- 如果变量的声明和赋值时同时进行的,可以忽略掉类型声明
六、类型总览

JavaScript中的数据类型
- string
- number
- boolean
- object
- null
- undefined
- bigint
- symbol
备注:其中object包括Array,Function,Date,Error…
TypeScript中的数据类型
上述所有JS类型
六个新类型
any
unknow
never
void
tuple
enum两个用于自定义类型的方式
type
enterface
在 JavaScript 中的这些内置构造函数:Number,String、Boolean他们用于创建对应的包装对象,在日常开发是很少用到,在TypeScript中也是同理,所以在TypeScript中进行类型声明时,通常都是用小写的 numbe,string,boolean
类型的大写和小写是有区别的,String和string不一样
let str1: string://TS官方推荐的写法str1 ='hello'
str1 = new String('hello');
let str2: String;
str2 = 'hello';
str2 = new String('hello');
console.log(typeof str1);
console.log(typeof str2);

- 原始类型和包装对象
- 原始类型:如number,string,boolean,在JavaScript中是最简单的数据类型,他们在内存中占用的空间少,处理速度快
- 包装对象:如Number对象,String对象,Boolean对象,是复杂类型,在内存中占用更多空间,在日常开发中很少有开发人员自己创建包装对象
- 自动装箱:JavaScript在必要时会自动降原始类型包装成对象,以便调用方法和属性

七、常用类型
1. any
any:任意类型,一个变量设置为any类型后,相当于对该变量关闭了ts的类型检测
//显式any
let g: any;
//隐式any:没有明确类型的变量
let h;
g = 10;
g = "10";
g = true;
any类型的变量,可以复制给任意类型的变量
let s: string;
//将any类型的值赋值给一个字符串时,不报错
//但是会把两者的类型检查都给关了(将一个true赋值给一个字符串类型的变量)
s = g;
2. unknown
unknown:未知类型
unknown可以理解为一个类型安全的any,适用于:不确定数据的具体类型
let i: unknown;
i = 10;
i = true;
i = "10";
//将unknown类型的值赋值给一个字符串时,报错:不能将类型“unknown”分配给类型“string”。
s=i;
unknown会强制开发者在使用之前进行类型检查,从而提供更强的类型安全性
//解决办法一:判断一下类型
if (typeof i === 'string') {
s = i;
}
//解决办法二:类型断言
//告诉编译器变量的实际类型
s = i as string;
//解决办法三:
s = <string>i;
- 读取
any类型数据的任何属性都不会报错,而unknown正好与之相饭
let str1: string
str1 = 'hello'
str1.toUpperCase()//无警告
let str2: any
str2 ='hello'
str2.toUppercase()//无警告
str2.qwe
str2.asd
str2.xyz
let str3: unknown
str3 = 'hello';
str3.toUpperCase();//警告:“str3”的类型为“未知”
str3.qwe();//警告:“str3”的类型为“未知”
//解决:
(str3 as string).toUpperCase()
3. never
never:任何值都不是,简而言之就是不能有值,undefined,null,…都不行
- 几乎不用
never去直接限制变量,因为没有意义
let a:never;
//已下对a的所有赋值都会有警告
a=1;
a=true;
a=undefined;
- never一般是TypeScript主动推断出来的
//指定a的类型为string
let a: string
// 给a设置一个值
a = 'hello'
if (typeof a === 'string') {
console.log(a.toUpperCase())
} else {
console.log(a)//Typescript会推断出此处的a是never,因为没有任何一个值符合此处的逻辑
}

- never也可以用来限制函数的返回值类型
//限制这个函数不需要有任何返回值
function demo(): never {
throw new Error('程序运行异常!')
}
let x = demo();
console.log(x)

4. void
- void通常用于函数返回值声明,含义:函数不返回任何值,调用者也不应依赖其返回值进行操作
function logMessage(msg:string):void{
console.log(msg);
}
logMessage('你好');
注意:
编码者没有编写 return 去指定函数的返回值,所以 logMessage 函数是没有显式返回值的,但会有一个隐式返回值,就是 undefined ;即:虽然函数返回类型为 void,但也是可以接受 undefined 的
简单记:undefined 是void可以接受的一种“空”
- 以下写法符合规范
// 无警告
function logMessagel(msg: string): void {
console.log(msg)
}
// 无警告
function logMessage2(msg: string): void {
console.log(msg)
return;
}
// 无警告
function logMessage3(msg: string): void {
console.log(msg);
return undefined
}
- 返回值是void和undefined还是有区别的
function demo1(): void {
console.log("@")
}
let result1 = demo1()
if (result1) {//报错:无法测试 "void" 类型的表达式的真实性。
}
function demo2(): undefined {
console.log("@")
}
let result2 = demo2()
if (result2) {
}
理解 void 与 undefined
void是一个广泛的概念,用来表达“空”,而“undefined”则是这种“空”的表现形式之一,因此可以说undefined是void能接受的“空”状态的一种具体形式。- 换句话说:
void包含undefined,但void表达的语义超越了单纯的undefined,它是一种意图上的约定,而不仅仅是特定值的限制。
总结:若函数返回类型为 void ,那么:
- 从语法上讲:函数是可以返回
undefined的,至于显式返回,还是隐式返回,这无所谓! - 从语义上讲:函数调用者不应关心函数返回的值,也不应依赖返回值进行任何操作!即使返回了 undefined 值。
5. object
关于object和Object,实际开发中用的相对较少,因为范围太大了
5.1.1. object
可以存储所有非原始类型,对象,函数,数组等,由于限制的范围比较宽泛,在实际开发中使用的相对较少

5.1.2. Object
- 可以存储:所以可以调用Object方法的类型
- 不可以存储:
undefined和null
由于限制的范围实在太大,用的不多

5.1.3. 声明对象类型
- 实际开发中,声明对象的形式
//限制person对象必须有name属性,age可选
let person1: { name: string, age?: number };
//可以用分号分隔
let person2: { name: string;age?: number };
//可以用换行符做分隔
let person3: {
name: string
age?: number
};
person1 = { name: '张三', age: 18 }
person2 = { name: '张三' }
//报错:对象字面量只能指定已知属性,并且“gender”不在类型“{ name: string; age?: number; }”中
person3 = { name: '张三', age: 18, gender: '男' }
- 索引签名:允许定义对象可以具有任意数量的属性,这些属性的键和类型是可变的,适用于具有动态属性的对象
let person1: { name: string, age?: number,[key:string]:any };
person3 = { name: '张三', age: 18, gender: '男' }//不报错
5.1.4. 声明函数类型

备注:
TypeScript中的=>在函数类型声明时表示函数类型,描述其参数类型和返回值类型JavaScript中的=>是一种定义函数的语法,是具体的函数实现- 函数类型声明还可以使用:接口,自定义类型等方式
5.1.5. 声明数组类型
//声明数组
let arr1:string[]
let arr2:Array<number>
arr1 = ['1', '2', '3']
arr2 = [1, 2, 3]
console.log(arr1, arr2)

6. tuple
元组(tuple)是一种特殊的数组类型,可以存储固定数量的元素,并且每个元素的类型是已知的且可以不同。元组用于精确描述一组值的类型,?表示可选元素。
//第一个元素必须是string类型,第二个元素必须是number类型。
let arr1:[string,number]
/第一个元素必须是number类型,第二个元素是可选的,如果存在,必须是boolean类型。
let arr2:[number,boolean?]
//第一个元素必须是number类型,后面的元素可以是任意数量的string类型
1et arr3:[number,...string[]]
//可以赋值
arr1=['he11o',123]
arr2=[100,false]
arr2=[200]
arr3=[100,'he11o','wor1d']
arr3=[100]
//不可以赋值,arr1声明时是两个元素,赋值的是三个
arr1=['hello',123,false]
7. enum
定义:枚举 enum 可以定义一组命名常量, 它能增强代码的可读性,也让代码更好维护
如下代码的功能是:根据调用walk时传入的不同参数,执行不同的逻辑,存在的问题是调用walk时传参时没
有任何提示,编码者很容易写错字符串内容;并且用于判断逻辑的up,down, left,right是连续且相关的一组值,那此时就特别适合使用
function walk(str: string) {
if (str === 'up') {
console.log("向【上】走");
} else if (str === 'down') {
console.log("向【下】走");
} else if (str === 'left'){
console.log("向【左】走");
} else if (str === 'right') {
console.log("向【右】走");
} else {
console.log("未知方向")
}
}
walk('up')
walk('down')
walk("left")
walk("right")
- 数字枚举
数字枚举是一种最常见的枚举类型,其成员的值会自动递增,且数字枚举还具备反向映射的特点,下面戴那种,可以发现:可以通过值来获取对应枚举成员的名称
enum Direction {
Up,
Down,
Left ,
Right
}
console.log(Direction);
//反向映射
console.log(Direction.Up);
console.log(Direction[0]);
//这行代码报错,因为枚举中的属性是只读的,不可修改
Direction.Up="shang";

也可以指定枚举成员的初始值,气候的成员只会自动递增
enum Direction {
Up=6,
Down,
Left ,
Right
}
console.log(Direction.Up);//6
console.log(Direction.Down);//7
使用数字枚举完成walk函数中的逻辑,会发现:代码更加直观易读,类型安全,易于维护
enum Direction {
up,
down,
left,
right
}
function walk(n: Direction) {
if (n === Direction.up) {
console.log("向【上】走");
} else if (n === Direction.down) {
console.log("向下走");
} else if (n === Direction.left) {
console.log("向【左】走");
} else if (n === Direction.right) {
console.log("向l右】走");
} else {
console.log("未知方向");
}
}
walk(Direction.up)
walk(Direction.down)
- 字符串枚举
丢失了反向映射 ,枚举成员是字符串类型
enum Direction {
Up = 'up',
Down = 'down',
Left = 'left',
Right = 'right'
}
console.log(Direction)

- 常量枚举
常量枚举是一种特殊的枚举类型,他使用const关键字定义,在编译时会被内联,避免生成一些额外的代码
编译内联:
“内联”就是TypeScript在编译时,会见枚举成员引用替换为他们实际的值,而不是生成额外的枚举对象,这可以减少生成的JS 代码,提高运行时性能
使用普通枚举:
enum Direction {
Up,
Down,
Left ,
Right
}
let x=Direction.Up;
编译后生成的js
var Direction;
(function (Direction) {
Direction[Direction["Up"] = 0] = "Up";
Direction[Direction["Down"] = 1] = "Down";
Direction[Direction["Left"] = 2] = "Left";
Direction[Direction["Right"] = 3] = "Right";
})(Direction || (Direction = {}));
let x = Direction.Up;
export {};
//# sourceMappingURL=Demo.js.map
使用常量枚举:
const enum Direction {
Up,
Down,
Left ,
Right
}
let x=Direction.Up;
编译后(在 "preserveConstEnums": false的前提下)
let x = 0 /* Direction.Up */;
export {};
//# sourceMappingURL=Demo.js.map
8. type
type 可以为任意类型创建别名,让代码更简洁,可读性更强,同时能更方便的进行类型服用和扩展
- 基本用法
类型别名使用type关键字定义,type后跟类型名称,例如下面代码中num是类型别名
type num=number;
let price:num;
price=100;
- 联合类型(或)
联合类型是一种高级类型,它表示一个值可以是几种不同类型之一
type Status =number|string
type Gender ='男'|'女'
function printstatus(data:Status):void{
console.log(data)
}
function printGender(data:Gender):void{
console.log(data)
}
printstatus(404)
printstatus('404')
printGender('男')
printGender('女')
- 交叉类型(并且)
type Area = {
height: number;
width: number;
}
type Address = {
num: number
cell: number
room: string
}
type House = Area & Address;
const house: House = {
height: 100,
width: 100,
num: 3,
cell: 3,
room: '241'
}
type Demo=number&string;
let demo:Demo;//这一行TS会自动推断出demo的类型是never
9. 特殊情况
- 在定义函数时,限制函数返回值为void,那么函数的返回值就必须是空
function demo():void{
return undefined;
//以下返回值均不合法
// return 100;
// return true;
// return null;
// return [];
}
- 使用类型声明限制函数的返回值为
void时,**TypeScript**并不会严格要求函数返回为空
type LogFunc=()=>void
//明明定义了返回值类型时void,但是代码中返回了100,却没有报错
const f1:LogFunc=()=>{
return 100;
}
const f2:LogFunc=()=>200;
const f3:LogFunc=function(){
return 300;
}

- 为什么?
const src=[1,2,3]
const dst=[0]
//完整写法
//这样写的返回值为undefined,符合函数定义时规定返回值为void
src.forEach((el)=>{
dst.push(el)
})
//箭头函数的形式
//写成箭头函数,默认dst.push(el)的返回值就是函数的返回值(返回一个数字)
//但是这个forEach函数定义时又被指明返回值为void,所以如果做严格的限制,就会报错
//不做限制,是为了让这种箭头函数写法可用
src.forEach((el)=>dst.push(el))
**void**作为函数返回值类型时,TypeScript 仅要求 “调用者不依赖该返回值”,也就是该返回值不可以拿来做任何事情,而不强制 “函数必须返回**undefined**”。
- 为什么 TypeScript 会这样设计?
这是为了灵活性。很多场景下,函数可能 “顺便” 返回了值,但调用者并不关心(比如 forEach 只需要执行回调的副作用,不处理返回值)。如果严格限制 void 必须返回 undefined,会导致很多合法用法报错(比如你例子中简化的箭头函数 (el) => dst.push(el))。
10. 属性修饰符
| 修饰符 | 含义 | 规则 |
|---|---|---|
public | 公开的 | 可以被:类内部,子类,类外部访问 |
protected | 受保护的 | 可以被:类内部,子类访问 |
private | 私有的 | 可以被:类内部访问 |
readonly | 只读属性 | 属性无法修改 |
11. 抽象类
- 概述:抽象类是一种无法被实例化(不可以使用new关键字创建)的类,专门用来定义类的结构和行为;类中可以写抽象方法,也可以写具体实现。抽象类主要用来为其派生类提供一个基础结构,要求其派生类必须实现其中的抽象方法。
- 简记:抽象类不能实例化,其意义是可以被继承;抽象类里可以有普通方法,也可以有抽象方法。通过以下场景,理解抽象类。
我们定义一个抽象类 Package,表示所有包裹的基本结构。任何包裹都有重量属性 weight,包裹都需要计算运费。但不同类型的包裹(如标准速度、特快专递)都有不同的运费计算方式,因此用于计算运费的 calculate方法是一个抽象方法,必须由子类来实现
abstract class Package {
//构造方法
constructor(public weight: number) { }
//抽象方法
abstract calculate(): number
//具体方法
print() {
console.log(`包裹的重量为${this.weight}`)
}
}
NormalPackage类继承了Package,实现了calculate方法
class NormalPackage extends Package {
constructor(
weight: number,
public unitPrice: number
) { super(weight) }
calculate(): number {
return this.weight * this.unitPrice
}
}
ExpressPackage类继承了Package,实现了calculate方法
class ExpressPackage extends Package {
constructor(
weight: number,
public unitPrice: number,
public expressFee: number
) { super(weight) }
calculate(): number {
if (this.weight > 10) {
return 10 * this.unitPrice + (this.weight - 10) * this.expressFee
} else {
return this.weight * this.unitPrice
}
}
}
总结:何时使用抽象类?
- 定义通用接口,为一组相关的类定义通用的行为(方法或属性)时
- 提供基础实现:在抽象类中提供某些方法或为其提供基础实现,这样派生类就可以继承并实现
- 确保关键实现:强制派生类实现一些关键性为
- 共享代码和逻辑:当多个类需要共享代码和逻辑时,抽象类可以避免代码重复
12. 接口
12.1. 定义类结构
interface PersonInterface{
name:string
age:number
speak(n:number):void
}
class Person implements PersonInterface{
constructor(
public name:string,
public age:number
){}
speak(n:number):void{
for(let i=0;i<n;i++){
console.log(`你好,我叫${this.name},今年${this.age}岁}`)
}
}
}
const p1=new Person('张三',18)
p1.speak(4)
12.2. 定义对象结构
interface UserInterface{
name:string
readonly gender:string//只读
age?:number
run:(n:number)=>void
}
const a:number=1
//这个接口当类型使用了
const user:UserInterface={
name:"张三",
gender:"男",
run:(n:number)=>{
console.log(`${n}km/h`)
}
}
12.3. 定义函数结构
interface CountInterface{
(a:number,b:number):number;
}
const count:CountInterface=(x,y)=>{
return x+y
}
12.4. 接口的合并(可重复定义)
interface PersonInterface {
name: string
age: number
}
interface PersonInterface {
gender:string
}
const p:PersonInterface={
name:'tom',
age:18,
gender:'女'
}
总结:何时使用接口?
- 定义对象的格式:描述数据模型,API相应格式,配置对象…是开发中用的最多的场景
- 类的契约:规定一个类需要实现哪些属性和方法
- 自动合并:一般用于扩展第三方库的类型,这种特性在大型项目中可能会用到
13. interface和type的区别
相同点:interface和type都可以用来定义对象结构,两者在许多场景中是可以互换的
不同点:
interface:更专注于定义对象和类的结构,支持继承,合并
type:可以定义类型别名,联合类型,交叉类型,但不支持继承和自动合并
14. interface和抽象类的区别
相同点:都用来定义一个类的格式
不同点:
接口:只能描述结构,不能有任何代码实现,一个类可以实现多个接口
抽象类:既可以包含抽象方法,也可以包含具体方法,一个类只能继承一个抽象类
15. 泛型
泛型允许我们在定义函数,类或接口时,使用类型参数来表示为指定的类型,这些参数在具体使用时,才能被指定具体的类型,反省能让同一段代码适用于多种类型,同时仍然保持类型的安全性
下面的代码中就是泛型,不一定非叫T,设置泛型后可在函数中使用T来表示类型
//泛型函数
function logData<T>(data:T){
console.log(data)
}
logData<number>(100)
logData<string>('hello')
//泛型可以有多个
function logData<T, U>(data1: T, data2: U) {
Date.now() % 2 ? console.log(data1) : console.log(data2)
}
logData<number, boolean>(100, true)
logData<string, string>('hello', 'world')
//泛型接口
function logData<T, U>(data1: T, data2: U) {
Date.now() % 2 ? console.log(data1) : console.log(data2)
}
logData<number, boolean>(100, true)
logData<string, string>('hello', 'world')
//泛型类
class Person<T>{
constructor(
public name:string,
public age:number,
public extraInfo:T
){}
speak(){
console.log(`${this.name} ${this.age} ${this.extraInfo}`)
}
}
const p1=new Person<number>('tom',18,100);
type JobInfo={
title:string;
company:string;
}
const p2=new Person<JobInfo>('tom',18,{title:'前端',company:'百度'});
八、类型声明文件
类型声明文件是TypeScript中的一种特殊文件,通常以..d.ts作为扩展名,它的主要作用是为现有的JavaScript代码提供类型信息,是的TypeScript能够在使用这些JavaScript库或模板时进行类型检查和提示
export function add(a,b){
return a+b;
}
export function mul(a,b){
return a*b;
}
declare function add(a:number,b:number):number;
declare function mul(a:number,b:number):number;
export{add.mul};
生活感悟
这周也是按照计划完成了TS的学习,但是感觉要将TS运用到项目中还是有点困难,毕竟写JS写习惯了。接下来就是复习基础知识,再找一些新的库看看
学习计划
感觉基础还是很不扎实,下周将JS高级和ES6复习一下,顺便看看uniapp,下个月就要开始写项目了,得重视起来

浙公网安备 33010602011771号