虽迟但到,都2022了,总该花时间看看ts吧
因为js是动态弱类型语言,为给js提供静态类型检查,提出了typeScript/flow
- 弱类型:例如var a=1,a=“String”,给a定义可以赋不同类型的值
- 静态类型:在编译阶段确定所有变量的类型
- 动态类型:在执行阶段确定变量类型
ECMAScript标准 推出静态类型检查之前,typeScript是解决次问题的最佳方案
什么是typeScript?
TypeScript 是 JavaScript 的一个超集,支持 ECMAScript 6 标准
三个要点
- 类型检查:在编译时进行类型检查,在编码阶段发现可能存在的隐患
- 语言拓展:typeScript会包括来自es6和未来提案中的特性,比如异步操作和装饰器,也从其他语言借鉴特性,如接口和抽象类
- 工具属性:typeScript可以编译成标准的JavaScript,typeScript更像是工具
typescript的数据类型
typescript的常用类型
原始类型:number/string/boolean/null/undefined/symbol 对象类型:object(对象、数组、函数等) 联合类型、自定义类型(类型别名)、接口、元组、字面量类型、枚举、void、any
1.类型注解
作用:为变量添加类型约束,相当于强类型语言中的类型声明。 解释:约定了什么类型,就只能给变量赋值该类型的值,否则就报错。 语法:(变量/函数):type
2.常用基础类型
let age: number = 18
let name: string = '名称'
let isloading: boolean = false
let a: null = null
let b: undefined = undefined
let b: symbol = symbol()
2.数组类型
let numbers: number[] = [1,2,3]
let strings: Array<string> = ['a','b','c']
// 联合类型 数组中既有number类型又有string类型
let arr:(number | string)[] = [1,'a','b',2]
3.类型别名(type)
类型别名:为任意类型起别名 使用场景:当同一个类型多次使用,可以通过类型别名,简化该类型使用。
type CustomArray = (number | string)[]
let arr1:CustomArray = [1,'a','b',2]
let arr2:CustomArray = ['a',1,'b',2]
4.函数类型
1.单独指定参数、返回值类型
function add(num1:number, num2:number):number{
return num1 + num2
}
const add = (num1:number, num2:number):number=>{
return num1 + num2
}
2.同时指定参数、返回值类型
const add:(num1:number, num2:number)=>number = (num1,num2)=>{
return num1 + num2
}
3.函数没有返回值。viod
function myName(name: string):void{
console.log('hello',name)
}
4.可选参数: 在可传可不传的参数名称后面添加?
function myName(a?:string,b?:string):void{
console.log('第一个参数',a,'第二个参数',b)
}
5.对象类型
1.使用{}来描述,属性名:类型; 方法名():返回值类型
let person:{name:string; age:number; sayHi():void}={
name:'xiaoming',
age:18,
sayHi(){}
}
2.可选属性/方法,可传可不传属性后加?
function myGet(config:{ url: string; method?:string }){
console.log(config)
}
6.接口(interface)
1.使用关键字interface声明
interface IPerson{
name: string
age: number
sayHi():void
}
let person1: IPerson{
name:'xiaoming',
age:18,
sayHi(){}
}
let person2: IPerson{
name:'xiaohong',
age:16,
sayHi(){}
}
2.⚠️注意:类型别名和接口的对比
相同:都可以给对象指定类型
不同:接口,只能为对象指定类型,类型别名可以为任意类型指定别名
3.接口继承:使用extends关键字
interface IPerson{
name: string
age: number
height: number
sayHi():void
}
interface MyPerson extends IPerson{
weight: number
}
7.元组(Tuple)
元组类型是另一种类型的数组,它确切包含多少个元素,和特定索引对应的类型。
let position:[number,string] = [1,'xiaoming']
8.类型推论
Typescript的类型推论机制会帮助提供类型,即类型注视可以不写 1.声明变量并初始化时 2.决定函数返回值时
9.类型断言
什么情况下需要用类型断言,当更加明确知道元素类型的时候,使用类型断言 使用 as 关键字 或者使用<>语法
const alink = document.getElementById('link') as HTMLAnchorELement
// 或者
const alink = <HTMLAnchorELement>document.getElementById('link')
补充一个小技巧,如何获取标签的更加具体的类型,通过浏览器的控制台console.dir(0 是在控制台html标签那里查看。
10.字面量类型
可以用字符串、数字、对象作为类型,
使用场景:一般配合联合类型使用,用来表示一组明确的可选值列表
例子: function changeDirection(direction:'up'|'down'|'left'|'right'){}
表示参数direction的值只能是up/down/left/right中任意一个
11.枚举 (enmu)
enmu Direction{
up,
down,
left,
rihgt
}
数字枚举:枚举的成员都有值,默认是0开始递增,也可以设置值
enmu Direction{
up = 10,
down,
left,
rihgt
}
字符串枚举:也可以设置为字符串
enmu Direction{
up = 'UP',
down = 'DOWN',
left = 'LEFT ',
rihgt = 'RIGHT'
}
function changeDirection(Direction){}
// 通过 .访问枚举的值
changeDirection(Direction.up)
值得一知:其他类型在编译为js代码时会自动移除,但枚举类型会在编译为js代码
12.any类型 (不推荐使用,会失去ts的意义)
当值的类型为any时候,可以对该值进行任意操作,不会有代码提示
let obj: any = {}
13.typeof
ts中的typeof可以在类型上下文中引用变量或属性的类型(类型查询) 使用场景:根据已有变量的值,获取该值的类型,来简化书写
typescript的高级类型
calss类
// class 基本使用
class Person {
age: number,
gender = '男' //可以省略类型注解,TS类型推论为string类型
}
// class 构造函数
class Person {
age: number,
gender = '男'
constructor(age: number, gender: string){
this.age = age
this.gender = gender
}
}
const p = new Person(16, '女')
console.log(p.age, p.gender) // 16 女
// class 实例方法
class Point {
x = 1
y = 2
scale(n: number){
this.x *= n
this.y *= n
}
}
const p = new Point()
p.scale(10)
console.log(p.x, p.y) // 10 20
// class 类继承的两种方式 1、extends(继承父类) 2、implements(实现接口)
// 1、extends 继承父类
class Animal{
move(){
console.log("Animal的move方法")
}
}
class Dog extends Animal{
name = '小狗'
bark(){
console.log("Dog的bark方法")
}
}
const d = new Dog()
d.move() // Animal的move方法
d.bark() // Dog的bark方法
console.log(d.name) // 小狗
// 2、implements 实现接口
interface Singable {
sing(): void
count: number
}
class Person implements Singable{
// Person类中必须提供Singable接口中指定的所有方法和属性
count: 5
sing(){
console.log('唱歌')
}
}
// class的可见性修饰符1、public(公有的)2、protected(受保护)3、private()
class Animal{
// public move(){
// protected move(){ //仅对声明所在的类和子类中(非实例对象)可见
private move(){ //只在当前类中可见,实例对象以及子类都不可见
console.log("Animal的move方法")
}
}
class Dog extends Animal{
name = '小狗'
bark(){
console.log("Dog的bark方法")
}
}
// class的 只读修饰符readonly(只能修饰属性,不能修饰方法)
class Animal{
// 表示只读,构造函数之外无法对属性进行赋值
readonly age: number = 2
constructor(age: number){
this.age = age
}
}
类型兼容性
// 类兼容性
class Point{x: number, y: number}
class Point2D{x: number, y: number}
class Point3D{x: number, y: number, z: number}
const p: Point = new Point2D()
const p: Point = new Point3D() //成员多的可以赋值给成员少的
// 接口兼容性
interface Point{x: number, y: number}
interface Point2D{x: number, y: number}
let p1: Point
let p2: Point2D = p1
interface Point3D{x:number, y:number, z:number}
let p3: Point3D
p2 = p3
// 函数之间兼容性,需要考虑参数个数、参数类型、返回值类型
参数少的可以赋值给参数多的
相同位置的参数类型要相同或者兼容
只关注返回值类型本身即可
交叉类型 &
交叉类型 (&):用于组合多个类型为一个类型(常用于对象类型)
// 交叉类型使用
interface Person{
name: string,
say(): number
}
interface Contact{
phone: string
}
type PersonDetail = Person & Contact
let obj:PersonDetail = {
name:'xiaoming',
phone:'123'
say(){
return 1
}
}
// 交叉类型(&)和接口继承(extends)对比
相同:都可以实现对象类型的组合
不同点:两种方式实现类型组合时,对于同名属性,处理类型冲突方式不同
泛型
泛型是在保证类型安全的同时,让函数等与多种不同类型一起工作,从而实现复用,常用于:函数、接口、class中。
// 一、泛型函数
function 函数名<指定具体类型>(value: 指定具体类型): 指定具体类型{return 值}
如:
function id<Type>(value: Type): Type{
return value
}
调用
const num = id<number>(10)
const str = id<string>('1')
const ret = id<boolean>(false)
简化调用泛型函数:因为TS内部会通过类型参数推断的机制,自动推出类型
let num = id(10)
let str = id('1')
let ret = id(false)
// 泛型约束:泛型函数的类型变量Type可以表示多个类型,但是无法访问任何属性
// 添加泛型约束收缩类型,1、指定更加具体的类型,2、添加约束
function id<Type>(value: Type): Type{
console.log(value.length) //无法访问length
return value
}
// 1.指定更加具体的类型
function id<Type>(value: Type[]): Type[]{
console.log(value.length) // 修改了Type为Type[],就可以访问数组的属性方法
return value
}
// 2.添加约束
interface ILength { length: number}
function id<Type extends ILength>(value: Type): Type{
console.log(value.length) // <Type extends ILength> 这样写达到访问length的目的
return value
}
id(['1','2'])
id('abcd') //字符串有length属性
id({length:5, name:'xiaoming'}) //传有对象可以,对象要有length属性,可以多传属性
id(100) // 这个错误,因为100是数字类型,没有length属性
// 多个泛型变量的情况( keyof )
// 使用keyof关键字 接收一个对象类型,生成其键名的联合类型
function getProp<Type, Key extends keyof Type>(obj: Type, key:key){
return obj[key]
}
getProp({name:'xiaoming', age: 18}, 'name') //实现了访问对象中存在的属性
// 二、泛型接口
interface idFunc<Type>{
id: (value: Type) => Type
ids: () => Type
}
let obj: idFunc<number> = {
id(value) { return value }
ids() { return [1,2,3]}
}
// 三、泛型类
class GenericNumber<NumType>{
defaultValue: NumType
add: (x: NumType, y: NumType)=> NumType
}
const myNum = new GenericNumber<number>()
myNum.defaultValue = 10
// 四、泛型工具类型
Partial<Type> 用来构造一个类型,将Type的所有属性设置为可选
Readonly<Type> 用来构造一个类型,将Type的所有属性都设置为readonly(只读)
Pick<Type,Keys> 从Type中选择一组属性来构造新类型
Record<Keys,Type> 构造一个类型,属性键为Keys,属性类型为Type
索引签名类型
索引签名类型使用场景:当无法确定对象中有哪些属性时,可以使用索引签名类型
//索引签名类型
interface AnyObject {
[key: string]: number
}
let obj: AnyObject = {
a: 1,
b: 2
}
映射类型
映射类型:基于旧类型创建新类型,减少重复。(只能在类型别名中使用,不能在接口中使用)
type Keys = 'x' | 'y' | 'z' | 'a'
type Type1 = {x: number, y: number, z: number, a: number} // 普通的方式,需要每一个都写
type Type2 = {[key in Keys]: number} // 通过[key in 遍历的类型],实现
//映射类型 keyof,根据一个对象类型生成一个对象类型
type Props = {a: number, b: string, c: number}
type Type3 = {[key in keyof Props]: number}