类型系统相关介绍


类型安全

  • 强类型
  • 语言层面限制函数的实参类型必须与形参类型相同
  • 语言中不允许任意的隐式类型转换
  • 弱类型
  • 语言层面不会限制实参的类型
  • 语言中允许任意的隐式类型转换

类型检查

  • 静态类型
  • 声明时,变量的类型便是明确的
  • 声明后,变量的类型就不允许再修改
  • 动态类型
  • 在运行阶段,才能够明确类型变量
  • 变量的类型可以随时发生变化
  • 可理解为,动态类型的变量是没有类型的,而变量的值是有类型的

强类型语言优势

  • 错误更早暴露
  • 代码更智能,编码更准确
  • 重构更牢靠
  • 减少不必要的类型判断

 

TypeScript


安装

yarn add typescript --dev

初始化

yarn tsc --init

配置

// tsconfig.json
"target": "es5" // 编译转化后的语言版本
"module": "commonjs" // 编译模块化方式配置
"outDir": "dist" // 编译后文件的输出路径
"rootDir": "src" // 编译的源文件路径
"sourceMap": true // 开启源代码映射
"strict": true // 开启严格模式
"lib": ["es2015", "DOM"] // 标准库,添加标准库,使得编译能够识别新的语法和模式

编译

yarn tsc fileName.ts

设置中文输出报错消息

yarn tsc --locale zh-CN

原始数据类型类型控制

// 非严格模式下,string|number|boolean 可以是 null
const a: string = ''
const b: number = 100 // NaN // Infinity
const c: boolean = false // true

// 严格模式下只能是 undefined;非严格模式则二者皆可
const d: void = undefined

const e: null = null
const f: undefined = undefined

const h: symbol = Symbol()

Object 类型(泛指所有非原始类型的数据类型)的类型控制

const foo: object = function () {} // [] // {}

数组类型

const arr1: Array<number> = [1, 2, 3]
const arr2: number[] = [1, 2, 3]

元组(Tuple)的类型控制

const tuple: [string, number] = ['foo', 100]

枚举类型的类型控制

  • 如果没有设置默认值,则会默认第一项为 0,往后各项默认 +1
  • 如果只设置了前面的部分项,则往后的没有设置默认值的项也会默认 +1
  • 当有项设置默认值为字符串类型时,则需要手动添加默认值
  • 在枚举类型前添加常量声明 const 可以使得在编译时默认转化为常量,从而避免枚举类型穿透到编译结果文件中
const enum PostStatus {
    Draft = 0,
    Unpublished = 1,
    Published = 2
}
const post = { title: '', content: '', status: PostStatus.Draft }

函数类型的类型控制

function fun1 (a: number, b?:number = 18, ...rest: number[]): string {
    return 'fun1'
}
func1(100, 200)
func1(100)
func1(100, 200, 300)

任意类型的类型控制

function stringify (value: any) {
    return JSON.stringify(value)
}

隐式类型推断

当变量声明时没有设置类型,typescript 会依据变量后续的使用进行类型推断。

类型断言

在编写时,告知 typescript 某一个函数或者接口返回的数据类型

接口

  • TypeScript 中,通过 interface 来声明接口
  • 接口的作用,在于设置、规定一个对象的属性以及属性值的类型
interface Post {
    title: string
    subTitle?: string // 可选成员
    content: string
    readonly summary: string // 只读成员
}
function printPost(post: Post) {}
printPost({title: '', content: '', summary: ''})

class Person {
    // init
    public name: string // 访问修饰符,表公用属性,为默认属性,可不加
    private age: number // 访问修饰符,表私有属性,即只能在类的内部进行访问
    protected gender: boolean // 保护属性,也不能在类的外部进行访问,但可以在子类中进行访问
    readonly sex: string // 只读属性,初始化之后不允许再次修改
      
    constructor (name: string, age: number) {
        this.name = name
        this.age = age
    }
    
    sayHi (msg: string): void {
        console.log(`I am ${this.name}, ${msg}`)
    }
}

const tom = new Person('tom', 18)
console.log(tom.name) // tom
console.log(tom.age) // throw Error

抽象类

TypeScript 中,通过在 class 声明前加上 abstract 关键字来声明抽象类。抽象类只能被子类继承,而不能通过 new 关键字实例化

abstract class Animal {
    eat (food: string): void {}
    abstract run (distance: number): void
}

泛型

在定义函数的时候,不去指定类型,在调用时在进行类型指定

function createArray<T> (length: number, value: T): T[] {
    const arr = Array<T>(length).fill(value)
    return arr
}
const res = createArray<string> (3, 'string')

 

Flow


Flow.js 是 JavaScript 的一款数据类型检查器,它会依据变量注解的数据类型对变量进行类型校验。

安装

yarn add flow-bin --dev

初始化

flow init

使用

flow fileName

原始类型注解

const a: string = ''
const b: number = 100 // NaN // Infinity
const c: boolean = false // true
const d: null = null
const e: void = undefined
const f: symbol = Symbol()

数组类型注解

const arr1: Array<number> = [1, 2, 3]
const arr2: number[] = [1, 2, 3]
// 元组
const foo: [string, number] = ['foo', 100]

对象类型注解

const obj1: { foo: string, bar: number } = { foo: 'string', bar: 100 }
const obj2: { foo?: string, bar: number } = { bar: 100 }

const obj3: { [string]: string } = {}
obj3.key1 = 'value1'
obj3.key2 = 'value2'

函数类型注解

function foo (callback: (string, number) => void) {
    callback('string', 100)
}
foo(function (str, n) {
    // str ===> string
    // n ===> number
})

特殊类型

  • 直接规定数据的可用值
  • 直接规定数据的多个可用类型
const a: 'foo' = 'foo'
const type: 'success' | 'warning' | 'danger' = 'warning'

type StringOrNumber = string | number
const b: StringOrNumber  = 'string' // 100

const gender: ?number = undefined
// ===>
const gender: number | null | undefined = undefined

任意类型

// mixed 可视为所有类型的联合类型,为强类型,需要做好参数类型判断
function passMixed (value: mixed) {
    if(typeof value === 'string') {}
    if(typeof value === 'number') {}
}
passMixed('string')
passMixed(100)
// any,弱类型,不需要做类型判断(仅编写阶段)
function passMixed (value: any) {}

*存在问题

存在类型注解的编码并不能直接运行,需要通过编译去除掉类型注解

  • 解决方案一:flow-remove-types
// 安装
npm i flow-remove-types --dev
// package.json
"scripts": {
  "build": "flow-remove-types src -d dist/", // 指定导出路径
  "prepublish": "yarn run build"
}
// 使用
npm run build
  • 解决方案二:babel preset
// 安装
yarn add @babel/core @babel/cli @babel/preset-flow --dev
// 添加配置文件 .babelrc
{
  "presets": [
    "@babel/preset-flow"
  ]
}
// package.json
"scripts": {
  "build": "babel src -d dist/", // 指定导出路径
  "prepublish": "yarn run build"
}
// 使用
npm run build