类型概念

根据类型安全可以将编程语言的类型系统分为强类型或者弱类型。
根据类型检查可以将编程语言的类型系统分为静态类型和动态类型。

强类型vs弱类型

由于历史因素,强类型和弱类型并没有非常明确的定义。根据个人理解,可以用下面这句话区分强弱类型。

主要用以描述编程语言对于混入不同数据类型的值进行运算时的处理方式。强类型的语言遇到函数引数类型和实际调用类型不匹配的情况经常会直接出错或者编译失败;而弱类型的语言常常会实行隐式转换,或者产生难以意料的结果。

在下例中,调用printNumber的时候传入数字或者字符串均可,是一种弱类型语言。

function printNumber(number){
    console.log(number)
}
printNumber(100) //ok
printNumber('100') //ok

在下例中,printNumber明确要求传入int整型,如果调用时传入字符串就会在编译时出错,因此是强类型语言。

class Main{
    static void printNumber(int num) {
        System.out.printIn(num)
    }

    public static void main() {
        Main.printNumber(100) // ok

        Main.printNumber('100') // ok
    }
}

静态类型vs动态类型

静态类型指的是变量的类型在编译时总是已知的,也就是变量声明完成后,不能改变其类型。

class Main{
    public static void main() {
        int number = 100

        number = 50 //ok

        number = '50' // error, 尝试改变类型
    }
}

动态类型指的是变量的类型直到运行时才能确定,也就是变量声明完成后,可随意更改其类型。

function main() {
    let num = 100

    num = 50 // ok
    num = '50' // ok
}

js类型概述

众所周知,javascript是弱类型语言,也是一种动态类型语言。这是由语言设计时的局限性决定的,当时,js只是用来完成简单的功能,所以弱类型和动态类型可以更为方便。但是,现在js也能支持大型的应用开发,其类型的弊病就暴露出来。

setTimeout(() => {
    // 在这种情况下,开发和简单测试过程中不会发现问题,只有运行一段时间后才会爆出问题。
    console.log(a)
}, 3000000);

let obj = {
    // 如果想要更改此属性值,因为不知道有多少代码中引入此属性,所以不敢轻易更改。
    name: 'zhangsan'
}
console.log(obj.name)

flow

flow是一种JavaScript静态类型检查工具,通过类型注解的方式在项目编写过程中对类型加以限制,从而更早发现代码问题,有利于项目的开发和维护。

类型注解:通过:的方式对变量的类型加以限制。

/**
 * @flow
 */
function sum(a: number, b: number) {
    return a + b
}
sum(1, 2) // ok
sum('1', 2) //error
// 由于sum要求参数是数字,但是调用的时候传入了字符串,所以在检查的时候flow会报错。

类型推断:根据使用情况自动推断类型。

/**
 * @flow
 */
function square(a) {
    // 调用函数的时候传入字符串,所以函数会自动推断a参数为字符串,因为字符串不允许相乘,因此检查会报错。
    return a * a
}
square('a')

原始类型

原始类型对应js中的原始类型。

const a: string = 'foo'
const b: number = 1 // 也可以赋值NaN(NaN是一种特殊的数字类型)
const c: boolean = true // false
const d: void = undefined
const e: null = null
const f: symbol = Symbol()

数组类型

// 使用范型定义数组
const a: Array<number> = [1, 2, 3]
const b: number[] = [1, 2, 3]
// 使用元组定义数组类型:定义数组个数及每项类型。
const c: [string, number] = ['foo', 1]

对象类型

// 类似对象字面量的方式定义对象中每个属性的类型
const obj: {
    name: string,
    age: number,
    // 可选
    address?: string
} = {
    name: 'zhangsan',
    age: 18
}

函数类型

// 通过箭头函数的方式定义函数类型
function ajax(callback: (string, number) => void) {
    callback('zhangsan', 18)
}

特殊类型

字面量类型

// 指定一个字面量为一个参数的类型, 通常字面量类型会和下面的联合类型使用
const foo: 'foo' = 'foo'

联合类型

// 指定类型为多个字面量类型中的一个
const type: 'warning' | 'success' | 'error' = 'error'
// 指定类型为数组,数组可以包含数字或者字符串
const arr: Array<number | string> = [1, '2']

type关键字

// 通过type关键字定义一个类型,可以认为resultType是'warning' | 'success' | 'error'的别名
type resultType = 'warning' | 'success' | 'error'
// 使用时可以直接用resultType定义类型,方便复用
const type: resultType = 'error'

Maybe可空类型

// 通过?定义可空类型,相当于 number | void
let a: ?number = 1 
a = undefined

mixed, any

// 通过mixed定义任意类型,可以是基础类型中的任意一个
let a: mixed = 1 
a = 'foo'
// any也可以表示任意类型,表现上和mixed相似
let a: any = 1
a = 'foo'

mixed和any虽然表现相同,都代表任意类型,但是二者是不一样的,mixed虽然表示任意类型,但是它还是强类型。

function anytest(s: any) {
    return s.substr(0, 1)
}
// 使用any时,可以传入任意类型的值,虽然数字可能不存在substr方法,但是检查时不会报错
anytest(1)

function mixedtest(s: mixed){
    // 使用mixed时,当这么直接调用substr就会报错,因为可能传入number类型。
    // return s.substr(0, 1)
    // 此时需要判断参数类型
    if(typeof s === 'string') {
        return s.substr(0, 1)
    }
}
mixedtest(1)

其他类型

上面介绍了flow中常用的类型,其还包含一些不常用的类型,遇到后再补充。


carry
58 声望7 粉丝

学无止境