TypeScript类型注解详解

137 阅读4分钟

一. 类型注解的作用

let name:string = '字符串'
//1. 将来不能把其他类型的值赋值这个变量, 减少开发隐藏问题;
name = 100 // error
//2. 写代码有提示, 比如在VScode中, 在变量后边敲一个 . 可以直接看到当前类型所支持的方法或属性;
name.substr()

二. 有哪些数据类型?

  • JS已有类型:

    • 简单类型: number / string / boolean / null / undefined
    • 复杂类型: 数组 / 函数 / 对象(看代码!)
    // 例: 声明一个只能包含字符串类型的数组
    //数组类型注解1
    let arr: string[] = ['a', 'b']
    //数组类型注解2
    let arr: Array<string> = ['a', 'b']
    
    // 函数声明:  ts要求必须给函数参数定义类型, 而返回值会自动推断(可以不写)
    function addNum(a: number, b: number): number {
        return a + b
    }
    let fn = (a:number, b:number): number => {
        return a + b
    }
    // 函数的类型别名, ,有点像箭头函数 但不是 (通常是给箭头函数或者函数表达式使用, 不会给函数声明'function'使用)
    type FnType = (a:number, b:number) => number
    let add: FnType = (a, b) = {
        return a + b
    }
    // 可选参数, 使用参数? , 表示参数可传可不传, (注意 可选参数不能在必选参数前面), 也可用于对象属性, 表示可选属性(可有可无)
    let print = (name: string, gender?: string): void => {
        console.log()
    }
    
    // 对象类型
    // 最大的好处就是描述了对象结构, 以后用到此对象的时候, 编辑器可以直接提示对象里的属性和方法, 避免出错
    // 常见使用场景: 定义好后端api返回的数据结构, 每次使用就不用去看接口返回字段了
    let obj:{
        name: string,
        gender: string,
        sayHi: (content: string) => void
    } = {
        name: '小丽',
        gender: '未知',
        sayHi(content) {
            console.log('无语'+content)
        }
    }
    // 使用类型别名
    type Person = {
        name: string,
        gender: string,
        sayHi: (content: string) => void
    }
    let obj1:Person = {
        name: '小帅',
        gender: '男',
        sayHi(content) {
            console.log('无语'+content)
        }
    }
    //可选属性的一些问题
    let obj:{
        name: stringg,
        girlFriend: string,
        gender?: string
    } = {
        name: '小智',
        girlFriend: '小韩',
        gender: '男'
    }
    obj.gender.concat() //会报错, 因为gender是可选属性, 可能会不存在
    //可选链操作符, 解决可选属性 不确定的问题
    obj.gender?.concat()
    
  • TS新增类型:

    • 联合类型 (可以把类型使用 | 链接起来, 代表'或') (看代码!)
    //使用联合类型时, 代码提示只提示两种类型共有的方法
    let timer: number | null = null
    timer = setTimeout(() => {}, 2000)
    let arr:(number | string) = [1, 2, 'a']
    
    • 自定义类型 (类型别名, 使用关键字 type )
    //相当于把稍复杂的类型封装起来
    type ArrType = (number | string)[]
    let arr1:ArrType = ['a', 1, 2]
    let arr2:ArrType = [1, 2, 'c']
    type Person = {
        name: string,
        gender: string,
        age?: number,
        say: (msg:string) => viod
    }
    let obj:Person = {
        name: '小韩',
        gender: '女',
        age: 18,
        say: (msg) => {
            console.log(msg)
        }
    }
    //还可以组合使用
    type ItemType = number | string
    let str: ItemType[] = [1, 2, 3]
    
    • 接口 (用于限制对象的属性和方法, 使用interface)
    //interface 与 type 的区别:
    //    1. interface只能给对象指定类型, 而type可以给任意类型指定别名
    //    2. interface每一个属性后不用写逗号
    interface IPerson {
        name: string
        say: (name:string) => viod
    }
    let obj:IPerson = {
        name: '小丽',
        say: (name) => {
            console.log('哈哈哈'+name)
        }
    }
    
    • void (用于不需要返回值的函数, 表示空)
    // 如果不写return, ts自动推断类型为viod, 因为如果用undefined, 表示函数必须只能返回undefined
    function Fn(a, b): void {
        console.log(a, b)
    }
    
    • 字面量 (值必须为字面量值)
    // 常常搭配联合类型一起使用,  表示值只能为up 或 down 其中一个
    type Direction = 'up' | 'down'
    function changeDirection(direction: Direction) {
        console.log(direction)
    }
    changeDirection('up')
    
    • 元祖 (固定长度和类型的数组)
    // 使用场景: 记录坐标, 数组只有两个元素, 且都是数值型
    let arr: [number, number] = [39.1245, 116.4255]
    
    • 枚举enum 定义一组命名常量, 描述一个值, 值只能是这些命名常量中的一个
    // 使用场景: 用户选择上/下/左/右, 但是后端要的值为 0(上) 1(下) 2(左) 3(右)
    enum Direction {
        Up,  //0       不指定值 默认为0 1 2 3..  递增
        Down, //1
        Left, //2
        Right //3
    }
    function changeDirection(direction: Direction) {
        console.log(direction)
    }
    changeDirection(Direction.Up) //打印 0
    
    //也可以指定值
    enum Direction {
        Up = '上',
        Down = '下',
        Left = '左',
        Right = '右'
    }
    changeDirection(Direction.left) //打印 左
    
    // 个人理解类似于字典, 建立对应关系, 可以通过键找值, 也可以通过值找键
    // 内部实现 实际上就是js对象
    
    • any类型 表示可以是任何类型, 可以对其进行任意操作 (不建议使用, 会失去使用ts类型保护的优势, 变成anyscript)

三. insterface(接口)的继承

使用extends关键字, 实现接口的继承, 继承后者所有约束

interface IPerson {
    name: string
    age: number
    sayHi: () => void
}
//Istudent 具备 IPerson 的所有约束规则
interface Istudent extends IPerson {
    score: number
    sleep: () => void
}
let obj:interface = {
    name: '小智',
    age: 18,
    score: 130,
    sayHi: () => {
        alert('Hi')
    },
    sleep: () => {
        alert('我睡了')
    }
}

四. type怎么实现类似继承的效果?

type Person = {
    name: string,
    gender: string
}
// 使用 & 连接符, 表示既要满足前面的 也要满足后面的, 变相的实现继承
type Student = {
    score: number
} & Person

let obj: Student = {
    name: '小丽',
    gender: '男',
    score: 150
}