目录
一、什么是 TypeScript
TypeScript 是微软推出的一门语言,强类型语言
TypeScript 是 JavaScript 的父级,里面包含了 JavaScript 以及 ES567,它可以编译成 js
在 JavaScript 之上新增了类型和完整的面向对象功能
好处:使用 ts 编写的项目更加稳健,并且更容易扩展和维护
二、为什么要用 TypeScript
js 不能限制传递值的类型
function fn(a,b){
// 但是我只想做加法运算,使用 js 的话只能对传递的值进行判断
return a + b // 返回 12
}
fn(1,'2') // 运行完才发现传递的是个字符串,再回头去改,影响开发效率
ts 限制传递值的类型
function fn(a:number,b:number){
// 加法运算,传递的值不是 number 类型的话就会报错
return a + b // 返回 12
}
fn(1,'2') // 还没运行,传递的类型不一致就会报错,可以及时的更改,不用把问题放在后面
好处:将问题放在开发前,不用等到运行后才发现错误
三、环境安装
新增的语法,浏览器和 node 都是无法识别并执行的
需要工具将 ts 代码转换为 浏览器 或 node 识别的 js 代码
安装 node 和 npm ,npm 会和 node 一起被安装
1. 方式一
安装: npm install -g typescript
检验安装是否成功: tsc -v
用法:tsc -w ts文件名
作用:将 ts 文件转换成 js 文件
2. 方式二
安装:npm install -g ts-node
用法:ts-node ts文件名
作用:自动将 ts 代码转换成 js 代码
四、语法
1. 变量
声明变量时,必须指定变量的数据类型
用法:let name : string = '张三'
注意:变量值的类型和指定的类型不一致,数据无法存储,会报错
2. 数据类型的约束
2.1. undefined 与 null
js 中是变量的值
undefined:表示未初始化变量的值
null:变量指向一个空对象
ts 中是一种数据类型
undefined:表示未初始化变量的值,只能存储 undefined 的值
null:变量指向一个空对象,只能存储 null 的值
注意:因为 undefined 和 null 是其他类型的子类,所以这两个变量的值可以赋值给其他类型的变量
2.2. 联合类型
用法:let 变量名:类型1 | 类型2
可以让变量存储多种类型的值
作用:变量取值的时候,可以是两种类型当中的任意一种
2.3. any
any 的值可以存储任意类型的数据
2.4. 数组
所有值必须是 同一个 类型
// 写法1
let arr:number[]=[1,3,4,5]
// 写法2
// Array<number> 泛型集合,相当于 new Array
let arr:Array<number>=[1,3,4,5]
值必需是()中规定的类型
// 写法1(不需要按照类型的顺序写)
let arr1: (number | string | object)[] = ['1', 3, 8, '4', '4', '4', '4', '444', 789789,{
id:1,name:"李四"
}]
// 写法2(按照类型的顺序写)第一位为字符串,第二位为数值,类型必须一一对应
let arr: [string,number] = ['1', 3]
2.5. 对象
限制对象 属性值 的类型
// c?: number (缺省) 判断有没有 c ,有的话只能 number 类型,没有也可以。
// 不加 ? 就必须就 c 这个属性,并且是 number 类型
let obj: { n: number, c?: number } = { n: 11 }
3. 函数的约束
带返回值 number 返回对应的数据类型
function fn(a:number,b:number):number{
return a + b // 返回 12
}
fn(1,2)
不带返回值 void
function fn(a:number,b:number):void{
return a + b // 返回 12
}
fn(1,2)
4. interface
接口:自定义约束结构
// 1. 首字母一定要大写
// 2. 分号结尾
interface Data {
message: string;
success: boolean;
data: { list: {}[] };
}
// data 数据的类型规定按照 Data 自定义的
let data: Data = {
message: '成功',
success: true,
data: {
list: [
{ id: 1, name: '李四' }
]
}
}
继承:可以对之前的约束进行复用,在之前的基础上往上添加,可有可无的属性可以使用缺省 属性?:类型
interface Data {
message: string;
success: boolean;
data: { list: { id: number, name: string }[] }
}
// extends 继承 Data 的数据类型
interface Res extends Data {
children?: {}[]
}
// 使用 Res 定义的约束,Res 又继承了 Data 相当于 Res 的约束等于 Data 和它的自身的约束
let data: Res = {
message: '成功',
success: true,
data: {
list: [
{ id: 1, name: '李四' }
]
}
}
作用:将数据的类型进行单独维护,提高代码的灵活性
5. 类
写法
class Person {
// 需要给当前类的属性设置类型
name: string;
age: number;
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
run():string{
return this.name;
}
}
new Person('李四', 89)
6. 修饰符
readonly 只读
private 私有的,当前类使用
public 公共的,任何地方都可以访问
protected 受保护的,只在当前类和当前子类内部使用
7. 抽象类 abstract
定义抽象方法,不能实现具体的功能
子类必须对抽象方法进行重写执行不同的任务,除非子类为抽象类
抽象类不能 new,不能进行实例化
抽象类可以继承,如果要继承,就必循实现该类的抽象方法
抽象类存在的意义就是为了被继承
抽象类中的普通属性和普通方法都需要用子类的对象去调用
用法
abstract class Person {
// 抽象属性
abstract name: string
// 定义抽象方法,在子类中重写来执行不同的任务
abstract run(): string
}
class Son extends Person {
// 重写改属性 name 并赋值
name: string = '李四';
// 重写父类的方法,来执行不同的任务
run() {
return this.name
}
}
let son = new Son()
console.log(son.run());
作用:提取子类共有的属性以及方法,封装重复的功能
8. implement
对类的进行约束,让类必须这些方法和属性
interface ip1 {
name: string,
age?: number,
}
interface ip2 {
gender: string,
}
// 对这个类进行2个约束
class Person implements ip1,ip2 {
name: string
}
9. 泛型
什么是泛型
指定义函数、接口、类的时候,不预定指定具体类型,在使用时再指定类型的一种特性
函数的泛型写法
// 函数使用多个类型
function fun1<F, U>(arg: F, b: U) {
console.log(arg, b);
}
// number 对应 arg
// string 对应 b
fun1<number, string>(1, '111')
// T extends string 表示泛型 T 必须是 string 的子类
// 继承 string 类里面的 length 属性
// <T extends string | string[] 联合声明
function fun1<T extends string | string[]>(arg: T): number {
// 报错传递的值中没有 length 属性
return arg.length
}
console.log(fun1<string>('jkflda'));
console.log(fun1<string[]>(['jkflda','d','e']));
接口的泛型写法
interface Data<T> {
data: T
}
// 对函数的返回值进行约束
function init(): Data<object> {
return {
data: {}
}
}
class 的泛型写法
class Person<T, U>{
name: T;
age: U
constructor(name: T, age: U) {
this.name = name
this.age = age
}
}
let p = new Person<string, number>('lisi', 18)
console.log(p);
10. 装饰器
什么是装饰器
就是一个方法,可以注入到类、方法、属性参数上来 拓展 类、属性、方法、参数的功能
使用装饰器,必须在 tsconfig.json 中进行 experimentalDecorators": true 配置
类装饰器
类装饰器在类声明之前被声明(紧靠着类声明)。
类装饰器应用于类构造函数,可以用来监视,修改或替换类定义。
传入一个参数 要获取装饰器扩展的东西,需要把实例对象的类型设置为any
普通装饰器(无法传递参数)
// target = Person function fun(target: any) { // 在 Person 构造函数原型上添加一个 name 属性 target.prototype.name = "李四" // 在 Person 构造函数上添加 aaa 属性 target.aaa = '7777' } // 将当前类传递给 fun 函数 = @fun(Perosn) @fun class Perosn { uname: string constructor(uname: string) { this.uname = uname } } let p = new Perosn('张三') // 访问 Person 原型上的 name // @ts-ignore console.log('name', p.name); // 访问 Person 构造函数上的 aaa 属性 // @ts-ignore console.log(Perosn.aaa);
装饰器工厂(可传参)
装饰器工厂函数实际上就是一个高阶函数,在调用后返回一个函数,返回的函数作为装饰器函数。
// optios 传递的参数 function fun(options: any) { // target 类构造函数传递给装饰器函数 // 返回装饰器函数 return function (target: any) { // 在 p 构造函数原型上增加新的方法 target.prototype.get = () => { console.log(options); } } } // @符号后为调用工厂函数,依次从上到下执行,目的是求得装饰器函数 @fun({ name: "李四", age: 18 }) class P { } let p = new P() // @ts-ignore p.get() console.log(p);
装饰器组合
@符号后为调用工厂函数,依次从上到下执行,目的是求得装饰器函数。装饰器函数的运行顺序依然是从下到上依次执行。
写了工厂函数,从上到下依次执行,求得装饰器函数。
装饰器函数的执行顺序是从下到上依次执行。
// 装饰器函数 function demo1(target: any) { console.log('demo1'); // 6 } // 装饰器工厂 function demo2(value: any) { console.log('demo2'); // 1 return function (target: any) { console.log('内部 demo2'); // 5 } } // 装饰器函数 function demo3(target: any) { console.log('demo3'); // 4 } // 装饰器工厂 function demo4(value: any) { console.log('demo4'); // 2 return function (target: any) { console.log('内部 demo4'); // 3 } } @demo1 @demo2('') @demo3 @demo4('') class Person { } // 执行结果 // demo2 // demo4 // 内部 demo4 // demo3 // 内部 demo2 // demo1
属性装饰器
// options 传递的参数 function fun(options: any) { // target 类的原型对象 // attr 属性名 // 返回装饰器函数 return function (target: any, attr: any) { // 给类里面需要装饰的属性进行赋值 target[attr] = options // 在类中添加 age 属性 target.age = 18 console.log(target, attr) } } class Person { // 给装饰器工厂传递参数 @fun('张三') // @ts-ignore userName: string // 构造函数 constructor(name: any) { this.userName = name } } let p = new Person('ddd') console.log(p); console.log(p.userName); // 获取类的原型对象中的 age 属性 // @ts-ignore console.log(p.age);
方法装饰器
11. 注释
@ts-ignore 取消下一行的报错