Typescript相关学习

强类型和弱类型

  • 从类型安全的纬度区分 分为强和弱, 最开始是在函数参数中加类型限制, 基础理解: 强类型 不允许隐式类型转换 弱类型允许

静态类型和动态类型

  • 从类型检查的纬度,分为静态类型和动态类型, 是否允许变量申明后去修改变量值的类型

javascript是一个弱类型、 动态类型的语言,是一个任性的语言,失去了类型的约束是一个不靠谱的语言。

  • javascript是一个没有编译环节的是一个脚本语言

弱类型的一些问题

  • 必须要等到运行时才能发现语法异常
  • 类型不明确会造成函数功能发生异常
  • 隐式转换规则不清晰

强类型的一些优势

  • 错误可以提前暴露
  • 代码更智能、编码更准确
  • 重构会更牢靠
  • 减少代码层面不必要的类型判断

Flow


Flow javascript静态类型检查器

  • 通过类型注解来做类型检查

flow的基础使用

  • flow-bin 是flow的安装包,使用npm安装
  • 在需要flow检查的文件顶部加 @flow的注释,用来标识该文件需要flow来检查静态类型
  • 在文件代码中加入类型注解
  • 使用 yarn flow命令进行检查

在编译阶段移除类型注解

  • 安装 flow-remove-types
  • 执行命令 yarn flow-remove-types ./src -d dist 编译src目录下的代码,删除类型注解 到dist目录
  • babel中也有babel-flow插件可以删除类型注解

vscode中可以安装 flow-language-support 可以在编码阶段给出代码错误提示

flow的类型推断

function square(n) {
    return n * n
}
square('100') //这个时候flow就会提示类型错误,因为字符串是不能进行*运算的

类型注解(尽量添加类型注解、少交给类型推断)

const no: number = 1

function foo(): string { return '' }

function foo(): void { }

flow支持的原始数据类型

  • string number(NaN、 Infinity都是属于number类型) null undefind(需要使用void表示) Object Array Symbol

数组类型

const arr: Array = [1,2,3,4,5] //需要是用泛型定义数组中每一项的类型

const arr: number[] = [1,2,3,4,5]

const arr:[string , number] = ['foo', 1] //元祖, 一般函数返回多个不同类型的值的时候使用

对象类型

const obj: {foo?: string, bar: number} = {foo: 'string', bar: 100} //?表示可选

const obj: {[string]: string} = {} //允许添加多个字符串键,和value是string的值

函数类型

  • 函数主要限制参数类型 和返回值类型类型
  • 函数作为参数传递
    function foo( callback: (string, number) => void) { callback()}

特殊情况

const type: 'success' | 'warning' | 'danger' = 'danger'

type stringOrNumber = string | number = 123

const type1:stringOrNumber = 123

const type2:?number = null // 在number类型上扩展了 null和undefined

mixed和any类型,可表示任意类型

  • 区别 mixed还是强类型(不能直接使用字符串方法或数字方法) any还是一个弱类型(可以调用任意类型的方法)

内置API的检查

const app: HTMLelement | null = document.getElementById('app')

TypeScript


TypeScript是javascript的超集,比JavaScript多了一个类型检查系统和对es新特性的完全支持,最终会被编译成js应用,可以兼容到es3

TypeScript可以说是前端领域的第二语言,现阶段react、angular、vue3 都使用了。
缺点:

  • 本身多了很多概念(接口、泛型、枚举等等)
  • 对于小项目,typescript会增加很多类型申明的成本

ts基本使用

  • 安装typescript模块
  • 模块提供了tsc命令, tsc命令会编译ts文件到js(移除类型注解、编译最新的语法)

tsconfig

  • yarn tsc --init
  • 修改配置文件选项后,可直接执行yarn tsc进行ts的语法编译

ts基本类型

  • ts基本类型的使用和flow是一样的,需要注意的是标准库申明文件的使用(例如symbol是es2015申明文件里面申明的,而console是浏览器对象BOM里面提供的, DOM和BOM的申明文件都在DOM里面)

错误提示可以主动设置

  • 编译时加上 --local zh-CN
  • 编译器vscode中,在设置中搜索typescript的,可以语言就可以了

不同文件中命名冲突

  • 文件使用const等申明后是在全局作用下,那么在下一个文件中使用相同命名就会提示冲突,解决方案:
  • 1.加上立即执行函数,把作用域编程函数作用域
  • 2.添加 export {} 将当前文件编程一个模块,变成一个局部作用域

Object类型

  • object不单指{}, 也可以是数组和函数
  • 使用字面量写法的时候,需要值和申明需要完全一致,不能多也不能少。
    const obj:{foo: string} = {foo: '1234', more: 123} // 这个时候more:123就会报错

数组类型和flow使用一致

const arr: Array = [1,2,3,4,5] //需要是用泛型定义数组中每一项的类型

const arr: number[] = [1,2,3,4,5]

元祖类型

  • 可以理解为固定长度、固定元素类型的数组

枚举类型

  • 某个值固定只能使用某几个值

  • 枚举类型会入侵我们代码,简单来说,就是会改变我们编译后代码

  • 加了const就会变成常量枚举

      const enum statusProp  {
          start = 0,
          ing = 1,
          end = 2
      }
    
      const status: 0|1|2 = 1
      const status2 = statusProp.start
    

函数的类型约束

function fn (a: number, b: number) :string {
    return 'abc'
} //参数的形参和实参必须保持一致
fn(1,3)
// fn(1,3,2) // 2就会报错

任意类型--typescript不会是any类型的数据做类型检查

function stringify(value: any) {
    return JSON.stringify(value) //stringify可以接收任何类型的参数
}

隐式类型推断

  • 如果我没有写类型注解,typescript会根据我们写的代码来推断数据的类型

let age = 18; age = 'string' //这个时候就会报错,ts推断age为number类型

类型断言

有时候typescript无法推断出一个变量的类型,作为开发人员我们可以主动的判断出是什么类型。那么我们就告诉typescript这个变量的类型

const arr = [1,2,3,5,6]
const res = arr.find((e) => e>0)
const res1 = res as number
const res2 = res //在jsx环境下会和标签产生冲突
const num = 100 - res1

接口(可以理解为一个规范或者约定)interface 规范一个对象所拥有的属性

interface Content {
    title: string
    message: string
    desc?: string
    readonly btn: string
}

function printContent(content: Content) {
    console.log(content.title)
    console.log(content.message)
}
printContent({
    title: "haha",
    message: "this is"
})
// 动态类型
interface Cache {
    [key: string]: string
}
const cache: Cache = {}
cache.foo = "1234"

类(描述一类具体事物的抽象特征)以及类的修饰符

class Person {
    name: string
    private age: number //私有属性
    protected gender: boolean //对子元素public
    constructor(name: string, age: number) {
        this.name = name
        this.age = age
        this.gender = true
    }
    say (msg: string) :void {
        console.log(`my name is ${this.name}`)
    }
}

const ton = new Person('ton', 18)
ton.name
ton.age //私有属性无法访问

class Student extends Person {
    constructor(name: string, age: number) {
        super(name, age)
        console.log(this.gender)
    }
}

类与接口

接口约定了类必须实现的方法

interface EatAndRun {
    eat(food: string): void
    run(distance: number): void
}
interface Eat {
    eat(food: string): void
    run(distance: number): void
}
interface Run {
    run(distance: number): void
}
class Person1 implements EatAndRun {
    eat(food: string) {
        console.log(`慢慢的吃${food}`)
    }
    run(distance: number) {
        console.log(`双脚跑步${distance}`)
    }
}
class Animals implements Eat, Run {
    eat(food: string) {
        console.log(`呼噜呼噜的吃${food}`)
    }
    run(distance: number) {
        console.log(`四脚跑步${distance}`)
    }
}

抽象类 (可以约束类的成员,与接口不同的是,可以包含一些成员的实现)一般大的类,我们会使用抽象类

abstract class Animal { //使用类抽象类之后,该类不能使用new来实例化
    eat(food: string) {
        console.log(`呼噜呼噜的吃${food}`)
    }
    abstract run(distance: number): void //抽象方法
}

class Dog extends Animal {
    run(distance: number): void {
        console.log(`4脚爬行${distance}`)
    }
    
}
const dog = new Dog()
dog.eat('gutou')
dog.run(100)

泛型

我们在定义函数、接口、类的时候我们没有定义类型,在调用的时候传入类型

function creatNumArray(len: number, value: number): number[] {
    return Array(len).fill(value)
}

function creatStrArray(len: number, value: string): string[] {
    return Array(len).fill(value)
}

function creatArray(len: number, value: T): T[] {
    return Array(len).fill(value)
}

const arrs = creatArray(10, '2')
const arrn = creatArray(10, 1)

类型声明 declare

引入第三方模块的时候,函数或者类没有对参数进行限制,我们需要手动添加声明,或者安装对应的声明模块

你可能感兴趣的:(Typescript相关学习)