TypeScript语言前奏-Flow(08)

Part1 · JavaScript【深度剖析】

TypeScript语言

文章说明:本专栏内容为本人参加【拉钩大前端高新训练营】的学习笔记以及思考总结,学徒之心,仅为分享。如若有误,请在评论区支出,如果您觉得专栏内容还不错,请点赞、关注、评论。共同进步!

上一篇:【ECMAScript模板字符串】、【ES6参数】、【展开数组、对象】、【箭头函数】、【对象】、【代理Proxy】、【class类】、【set、map数据结构】

本篇开始,梳理一些TypeScript语言的知识。首先看一下关于强、弱类型的语言方面的知识。

一、强类型与弱类型、静态类型与动态类型

1.强类型与弱类型(类型安全)

①、强类型语言:强类型语言也称为强类型定义语言。是一种总是强制类型定义的语言,要求变量的使用要严格符合定义,所有变量都必须先定义后使用。java、.NET、C++等都是强制类型定义的。也就是说,一旦一个变量被指定了某个数据类型,如果不经过强制转换,那么它就永远是这个数据类型了。

1974年美国两个专家做出解释:语言层面限制函数的实参类型必须与形参类型相同

个人理解:强类型语言不允许有各种方式的隐式转换

例如你有一个整数,如果不显式地进行转换,你不能将其视为一个字符串。

class Main {
    // 接受一个整形的参数
    static void foo(int num) {
        System.out.println(num);
    }
    
    public static void main(String[] args) {
        Main.foo(100);  // ok
        
        Main.foo("100"); // error "100" is a string,不允许传入其他类型的值
        
        Main.foo(Interger.parseInt("100"))  // ok,强制类型转换
    }
}
D:\DeskTop\lagou\Flow>python
Python 3.7.0 (v3.7.0:1bf9cc5093, Jun 27 2018, 04:59:51) [MSC v.1914 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> '100' - 50
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for -: 'str' and 'int'
>>> abs('foo')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: bad operand type for abs(): 'str'
>>>

与其相对应的是弱类型语言:数据类型可以被忽略的语言。它与强类型定义语言相反, 一个变量可以赋不同数据类型的值。

**②、弱类型语言:**弱类型语言也称为弱类型定义语言。与强类型定义相反。像vb、php、js等就属于弱类型语言,语言层面不会限制实参的类型。

个人理解:弱类型语言则允许任意的数据隐式类型转换

function (num) {
    console.log(num);
}
foo(100); // ok
foo('100');  // ok
foo(parseInt('100'));  // ok
Microsoft Windows [版本 10.0.18363.1139]
(c) 2019 Microsoft Corporation。保留所有权利。

D:\DeskTop\lagou\Flow>node
Welcome to Node.js v12.19.0.
Type ".help" for more information.
> '100' - 50
50
> Math.floor('foo')
NaN
> Math.floor(true)
1

JavaScript中所有的类型错误都是在代码执行(逻辑判断)的过程中抛出的,并不是在语法层面进行抛出。

2.静态类型与动态类型(类型检查)

  • 静态类型语言

    一种在编译时,数据类型是固定的语言。大多数静态类型定义语言强制这一点,它要求你在使用所有变量之前要声明它们的数据类型。Java和C是静态类型定义语言。

  • 动态类型语言

    一种在执行期间才去发现数据类型的语言,与静态类型定义相反。VBScript和Python是动态类型定义的,因为它们是在第一次给一个变量赋值的时候找出它的类型的。

    var foo = 100;
    foo = 'bar';
    console.log(foo);
    // 在JavaScript中,变量是没有类型的。而变量中存放的值是有类型的
    

在这里插入图片描述

3.JavaScript类型系统特征

JavaScript为弱类型且动态类型,语言本身的系统非常薄弱,甚至说JavaScript根本没有类型系统----【任性】,其缺失类型系统的可靠性【不靠谱】。

早期JavaScript的目的并没有想到去处理很多程序,很多项目只有几十行上百行代码。

3.弱类型的问题及强类型的优势

  • 弱类型的问题,运行阶段才能发现类型异常问题。例如在setTimeout中,当时间结束时才会发现错误,如果调试过程中没有等到足够的时间,那么这个类型错误就会形成隐患。

示例一:运行时才能发现错误

const obj = {};
obj.foo();

// obj.foo();
// ^
//
// TypeError: obj.foo is not a function
// at Object.<anonymous> (D:\DeskTop\lagou\Flow\01\01-getting-started.js:2:5)
// at Module._compile (internal/modules/cjs/loader.js:1015:30)
// at Object.Module._extensions..js (internal/modules/cjs/loader.js:1035:10)
// at Module.load (internal/modules/cjs/loader.js:879:32)
// at Function.Module._load (internal/modules/cjs/loader.js:724:14)
// at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:60:12)
// at internal/main/run_main_module.js:17:47

示例二:非预期结果

function sun(a, b) {
	return a + b;
}

console.log(sum(100, 100));
console.log(sum('100', '100'));

// 200
// 100100

示例三:数据错误

const obj = {};
obj[true] = 100
console.log(obj['true']);  // 100
  • 强类型的优势:错误更早的暴露、代码更智能,编码更准确、重构更方便、减少不必要的类型判断

二、Flow概述及方法

1.概述

flow是 facebook 出品的 JavaScript **静态类型检查工具,https://flow.org/en/docs/usage/**这是其官方文档链接。Vue.js 的源码利用了Flow 做了静态类型检查。

JavaScript动态类型语言,它的灵活性有目共睹,但是过于灵活的副作用是很容易就写出非常隐蔽的隐患代码,在编译期甚至看上去都不会报错,但在运行阶段就可能出现各种奇怪的 bug

类型检查的定义:类型检查,就是在编译期尽早发现(由类型错误引起的)bug,又不影响代码运行(不需要运行时动态检查类型),使编写 JavaScript 具有和编写 Java 等强类型语言相近的体验

在vue中使用Flow做静态类型检查,是因为 BabelESLint 都有对应的 Flow 插件以支持语法,可以完全沿用现有的构建配置,非常小成本的改动就可以拥有静态类型检查的能力

类型注解

function add(x: number, y: number): number {
  return x + y      //x的类型是number,y的类型是number,函数的返回值类型是number
}
add('Hello', 11)

2.快速上手

  1. 初始化模块

    • yarn init -yes
  2. 安装flow

    • yarn add flow-bin -dev
  3. 使用flow类型注解

    • 必须在文件文件开始处标记:@flow

    • 关闭VS Code语法校验:setting,搜索JavaScript validate,找到enable,取消勾选

    • // @flow
      
      function sum(a:number, b:number) {
      	return a + b;
      }
      
      sum(100, 100)
      sum('100', '100')
      
      let num:number = 100
      num = '100'
      
  4. 使用

    • yarn flow init
      yarn flow  # 第一次会很慢,后续会很快
      # yarn flow stop # 结束flow
      
      #Error ---------------------------------------------------------------------------------------------------- 01/01.js:8:12
      
      #Cannot call `sum` with `'100'` bound to `b` because string [1] is incompatible with number [2]. [incompatible-call]
      
      #   01/01.js:8:12
      #   8| sum('100', '100')
      #                 ^^^^^ [1]
      
      #References:
      #   01/01.js:3:26
      #   3| function sum(a:number, b:number) {
      #                               ^^^^^^ [2]
      
      

3.编译移除注解

  • 方案一:自动移除类型注解,官方提供的模块:flow-remove-types
yarn add flow-remove-types --dev
yarn flow-remove-types . -d dist
# yarn flow-remove-types [需要移除注解的文件,一般为src] -d [输出目录,如果不存在则新建,一般为dist]
  • 方案二:babel
yarn add @babel/core @babel/cli @babel/preset-flow --dev

然后在项目中添加项目文件-【.babelrc】,然后在文件中输入:

{
    "presets":["@babel/preset-flow"]
}

随后使用命令行

yarn babel src -d dist

4.开发者工具插件

**VS Code搜索插件【flow language support】,flow官方提供的插件,可以实时显示类型异常。**默认情况下,修改完代码,需要重新保存后才会检测类型异常。

flow官网:https://flow.org/en/docs/editors

5.类型推断

flow支持在代码编写过程中就进行类型推断,例如下面代码中,需要算一个数的平方,当传入非数字类型时,flow会进行代码提示,抛出类型错误。

// @flow

function square(n: number) {
	return n * n;
}

square('100')

6.类型注解

在绝大多数情况下一样,它可以帮我们推断出来变量,或者是参数的具体类型,但是没有必要给所有的成员都去添加,它可以更明确的去限制类型注解,而且对我们后期去理解,也是有帮助的可能去使用。

let num:number = 100;
// num = 'string',此时只能赋值数字类型

function foo():number {
    return 100
}
// 此时函数只能返回数字类型,如果函数没有返回值,默认返回undefined,那么也会提醒报错。没有返回值的函数,我们需要将函数返回值类型标注为void

7.原始类型

在用法上flow,几乎没有任何的难度,无外乎就是使用flow命令去根据我们代码当中添加的类型注解,去检测我们代码当中的那些类型使用上的异常。值得我们再去了解的无外乎就是flow当中,具体支持哪些类型,以及,我们在类型注解上有没有一些更高级的用法,这里呢,我们具体来看。

flow中能使用的类型有很多,最简单的就是JavaScript中的原始类型,目前原始类型共有6中,number、Boole、string、null、undefined、symbol。以下进行快速尝试:

/**
 * 原始类型
 *
 * @flow
 */

const a: string = 'foobar'

const b: number = Infinity // NaN // 100

const c: boolean = false // true

const d: null = null

const e: void = undefined

const f: symbol = Symbol()

8.数组类型

/**
 * 数组类型
 *
 * @flow
 */

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

const arr2: number[] = [1, 2, 3]

// 元组
const foo: [string, number] = ['foo', 100]

9.对象类型

/**
 * 对象类型
 *
 * @flow
 */

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'

10.函数类型

/**
 * 函数类型
 *
 * @flow
 */

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

foo(function (str, n) {
  // str => string
  // n => number
})

11.特殊类型

/**
 * 特殊类型
 *
 * @flow
 */

// 字面量类型

const a: 'foo' = 'foo'

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

// ------------------------

// 声明类型

type StringOrNumber = string | number

const b: StringOrNumber = 'string' // 100

// ------------------------

// Maybe 类型

const gender: ?number = undefined
// 相当于
// const gender: number | null | void = undefined

12.Mixed与Any

/**
 * Mixed Any
 *
 * @flow
 */

// string | number | boolean | ....
function passMixed (value: mixed) {
  if (typeof value === 'string') {
    value.substr(1)
  }

  if (typeof value === 'number') {
    value * value
  }
}

passMixed('string')

passMixed(100)

// ---------------------------------

function passAny (value: any) {
  value.substr(1)

  value * value
}

passAny('string')

passAny(100)

今日分享截止到这里,明天更新:TypeScript部分。

记录:2020/11/10

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

5coder

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值