前言
最近项目中引入了TS,打算深入学习一下TS
typescript是js的超集,它可以编译成纯js,ts可以在任何浏览器和操作系统上运行,并且是开源的。
1、安装
全局进行安装:npm install -g typescript
2、查看是否安装成功
在cmd中输入命令 tsc -v 查看是否下载成功,输入命令出现版本号则下载成功
TS类型
ts支持与js几乎相同的数据类型,此外还提供了枚举类型,ts支持的类型包括:布尔、数字,字符串、数组、枚举、any、never、null、undefined、object、void、类型断言
- TS出现是弥补js的类型缺失
- TS代码要运行在浏览器中,需要进行类型转换,转换为js代码
- TS类型包含所有JS类型null、undefined、string、number、boolean、symbol
- 还包含void、never、enum、unkonow、any以及ts自定义的type和interface
变量声明
var/let/const 标识符:数据类型 = 赋值
const data: string = 'hello
const userName: string
userName = '小王子的玫瑰花'
userName = 10
如果没有明确指定类型,TS会隐式推出一个类型,这类型根据赋值自动类型推断,没有赋值则为any类型。
const data2: any
let data2
基础类型
// string 字符串类型,可以使用单引号、双引号、反引号表示
const a: string = 'hello'
// number 数字类型,同样支持进制表示,但也不区分整数和浮点数
const b: number = 10
// boolean 布尔类型只有两个值:true 和false
const c: boolean = true
// undefiend null 既是实际的值,也是类型
const n: null = null
const u: undefiend = undefiend
// bigInt
const bInt: bigint = 10n
// Symbol
const s1 = Symbol('s1')
const s2 = Symbol('s2')
const info = {
[s1]: '张三',
[s2]: '李四'
}
数组和元组
// Array<元素类型> 这种写法可能存在与jsx 冲突问题
const arr1: Array<number> = [1, 2, 3]
// 元素类型后面接上[],表示由此类型元素类型组成的一个数组
const arr2: number[] = [1, 2, 3]
// 数组里面可能有字符串和数字
const arr3: (number | string)[] = [1, 2, '小王子的玫瑰花']
// 元组已知元素数量和类型的数组,元组一定要指明类型
const tuple: [string, number] = ['张三', 18]
对象类型
- TS中的对象类型泛指所有的非原始类型,比如:对象、数组、函数
- 使用object定义一个新对象,但是这个对象不能设置新数据也不能修改来数据
const obj: Object = {
name : '测试'
}
obj.age = 20
obj.name = '王麻子'
如下所例所限制对象类型更为精确,可限制每个属性的类型
const p1: { name: string; age: number } = { name: '王小二', age: 18 }
const p2: {name: string; age?: number } = { name: '云母' }
any、unknown、never
- 无法确定一个变量的类型,可使用
any
,此时在其身上做任何操作都是合法的,即使访问了一个不存在的属性 - 如果某些情况处理类型过于繁琐,或者在引入一些第三方库时,缺失了类型注解,这个时候 我们可以使用 any,更多是为了兼容老代码
unknown
类型表示一个值可以是任何类型,它是所有类型的父类型,任何类型都可以赋值给 unknown 类型,但是 unknown 类型只能赋值给 any 类型和 unknown 类型本身- 类似
any
,与any
类型不同的是,unknown
类型的变量不能直接赋值给其他类型的变量,也不能调用其上的任何方法或属性,除非先进行类型检查或类型断言,这样确保运行时的类型安全 - 默认在其操作都是不合法的,主要是在编写通用代码时,例如编写库或框架时,需要处理来自不同来源的数据,但又不确定数据的类型
never
类型表示这种永不存在值的类型- 它是一个底层类型,不是任何类型的子类型,也没有任何子类型
函数类型
- 声明函数时,可以在每个参数后添加类型注解,声明其参数类型
- 同样也可以声明返回值的类型,不过也可以不写让 TS 自动推导
- 函数参数的一般顺序 必传参数 - 有默认值的参数 - 可选参数
// nl 接受 number 类型的参数,同样返回number 类型
function fn1(n1: number): number{
return n1
}
// 箭头函数写法
const fn2:(n1:number)=>number=n1=>{
return n1
}
// n1的默认值是10,n2 是可选类型参数,...args 是剩余参数,代表接受一个只读的number类型数组
// 返回值是 void 代表可以返回 undefined 或者不return
const fn3 =(n1:number=10,n2?: number,...args:readonly number[]):void =>{
return undefined
}
枚举类型
- 枚举类型将一组可能出现的值,一个个列举,定义在一个类型中,这个类型就是枚举
这种字符串的枚举可能使用 type Direction = 'LEFT' | 'RIGHT' | 'TOP' | 'RIGHT'
可能会更好点
type Direction = 'LEFT' | 'RIGHT' | 'TOP' | 'BOTTOM'
function turnDirection(direction: Direction) {}
turnDirection('LEFT')
interface 和 type
- 使用 interface 定义接口,使用 type 定义类型别名
- 都可以约束对象的结构
区别
- interface 只描述对象,type 则可以描述所有数据
- interface 使用 extends 来实现继承,type 使用 & 来实现交叉类型
- interface 会创建新的类型名,type 只是创建类型别名,并没有创建新类型
- interface 可以重复声明扩展,type 则不行(别名是不能重复的)
// 方式一:使用interface
interface IPoint {
X: number,
readonly y: number,
z?: number
}
// 方式二:使用type
type Poin {
x: number,
y: number
}
类型、非空、常量断言
- 类型断言
as
,当 TS 无法获取到具体的类型信息,就需要使用类型断言(Type Assertions) - 它可以允许我们断言成更具体或者不太具体的(比如any)的类型
const arr = [110, 120, 119, 112]
const res = arr.find(i => i > 0)
const num1=res as number // 断言res 是number
const num2=<number>res // 或者这种方式。JSX下不能使用
// 这种获取元素方式 TS 只知道该函数会返回HTMLImageElement不知道具体类型
const el= document.getElementById('img')as HTMLImageElement
el.src ='url地址'
- 非空类型断言
!
,当我们确定参数有值,需要跳过 TS 对它的检测的时候可以使用
function fn(msg?: string) {
console.log(msg!.length)
}
- 常量断言
as const
,将类型尽量收窄到字面量类型,如果用在对象后面,相当于给对象里面每个成员加上readonly
const arr = [1, 'hello'] as const
const obj: {
readonly a: 1,
readonly b: 2
}
const obj = {
a: 1,
b: 2
} as const
基本类型和普通对象
// 简单类型兼容
type StringOrNumber = string number
const msg:String0rNumber = 'hello' // 较小的类型可以赋值给较大的类型
// 普通对象兼容
interface Person {
name: string,
age: number
}
let user = {
name: '测试',
age: 18,
id: 1
}
const p:Person=user // 属性多的可以赋值给属性少的
function printPerson(p: Person) {}
printPerson(p)
printPerson({
name: 'zhangsan',
age: 18,
id: 1
})
类
- ES6 之前使用函数实现类,ES6可以使用 class 关键字声明一个类
- 在默认的
strictPropertyInitialization
模式下面我们的属性是必须在constructor
初始化的,如果没有初始化,那么编译时就会报错,如希望此模式下不报错,可以使用name!: string
的语法 - 类拥有自己的构造器
constructor
,当我们通过new
关键字创建一个实例时会被调用,类中定义的函数叫方法
1、基本使用
class Person {
name: string,
age: number
constructor(name:string, age:number) {
this.name = name
this.age = age
}
eating(){
console.log(this.name +'eating')
}
}
const p = new Person('测试',18)
console.log(p.name,p.age)// 测试 18
p。eathing()
2、类的继承:使用 extends
关键字来实现继承,子类中使用 super
来访问父类
class Student {
gender: string
constructor(name: string, age: number, gender: string) {
// super调用父类的构造器
super(name, age)
this.gender = gender
}
// 重写
eathing() {
console.log('student eating')
// 内部调用父类的 eating 方法
super.eating()
}
studying() {
console.log('studying')
}
}
const stu = new Student('王小二',18,'男')
console.log(stu.name, stu.age, stu.genter)
stu.eathing() // student eathing 王小二eathing
3、类的成员修饰符
- 在 TS 中,类的属性和方法支持三种修饰符:
public
、private
、protected
- public:类外可见,默认编写的属性就是 public 的
- protected:类和子类中可见
- private:仅自身类可见
- #属性:实现私有属性,并且类型擦除之后还有效
class Person {
private name: string = ''
protected age:number = 0
constructor(name: string,age: number){
this.name = name
this.age = age
}
// 封装了两个方法,外部只有通过方法来访问和设置内部私有属性name
getName() {
return this.name
}
setName(newName: string) {
this.name = newName
}
}
class Student extends Person {
// 构造器 private 就不能使用 new Student 创建实例
private constructor(name: string,age: number) {
super(name, age)
}
getAge() {
return this.age
}
static create(name: string,age: number){
return new Student(name, age)
}
}
泛型
- 定义函数的时候不决定参数的类型
- 而是让调用者使用尖括号形式传入对应函数
- 比如我们实现一个函数,传入一个参数并返回它,保证这个参数和返回值类型一致
function fn<Type>(args: Type): Type {
return args
}
2、传入多个类型
function fn<T,E>(n1:T,n2:E) {}
其中,T,E 这些都是我们可以自定义的,它们代表的意义是
- T(Type):类型
- K(key)、V(value):,键值对
- E(Element):元素
- O(Object):对象
内置类型声明
- TS 帮我们内置了一些运行时标准化 API 的声明文件
- 比如
Function
、String
、Math
、Date
、RegExp
、Error
等内置类型 - 也包含运行环境中的 DOM 、BOM API,比如
Window
、Document
、HTMLElement
、Event
、NodeList
等 -
const b: Boolean = new Boolean(true) const n: Number = new Number(true) const s:String = new String('云牧牧') const d: Date = new Date() const r:RegExp =编辑/^hello/ const e: Error =new Error('err')