Typescript类型系统FLOW静态检查基本规范


Posted in Javascript onMay 25, 2022

Typescript是一门基于JavaScript之上的语言,重点解决了JavaScript自由类型系统的问题。

使用Typescript可以大大提高代码的可靠程度。

类型系统

强类型和弱类型(类型安全)

强类型:语言层面限制函数的实参类型必须与形参类型相同

Typescript类型系统FLOW静态检查基本规范

弱类型:语言层面不会限制实参的类型

Typescript类型系统FLOW静态检查基本规范

由于这种强弱类型之分根本不是某一个权威机构的定义,所以导致后人对这种鉴定方式的细节,出现了不一致的理解。但整体上大家的鉴定方式都是在描述强类型有更强的类型约束,而弱类型中几乎没有什么约束。

强类型语言中不允许有任意的隐式类型转换,而弱类型语言中则允许任意的数据隐式类型转换。

强类型不允许随意的隐式类型转换,而弱类型则是允许的。

变量类型允许随时改变的特点,不是强弱类型的差异。

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

  • 静态类型:一个变量声明时它的类型就是明确的,而且声明过后,它的类型就不允许再修改。
  • 动态类型:运行阶段才能够明确变量类型。动态类型语言中的变量没有类型,变量中存放的值是有类型的。

JavaScript就是动态型语言,而且变量的类型随时可以改变。

常用编程语言:

Typescript类型系统FLOW静态检查基本规范

JavaScript自由类型系统的问题

JavaScript是弱类型且动态类型,甚至可以说它没有类型。它的特征就是[任性]、[不靠谱],缺失了类型系统的可靠性。

JavaScript没有编译环节

大规模应用下,弱类型/动态类型这种优势就变成了短板。

弱类型的问题:君子约定有隐患,强制要求有保障。

强类型的优势:

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

Flow静态类型检查方案

  • Flow是JavaScript的静态类型检查器。
  • 弥补了JavaScript的不足,为JavaScript提供了更完善的类型系统。
  • 工作原理就是通过在代码当中添加一些类型注解方式来去标记代码中变量或参数应该是什么类型的。
//@flow
function sum(a: number, b: number) {
    return a + b
}
console.log(sum(10, 20));
console.log(sum('10', '20'));

Flow只是一个小工具。

安装:flow-bin

通过编译除注解

  • 1.安装flow-remove-types依赖
  • 2.使用JavaScript编译工具babel配合flw插件

flow开发者工具:flow language support

类型注解

function add(a:number,b:number){
	return a+b
}
let num:number = 90
function foo():void{}

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()

flow数组类型

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

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'

flow函数类型

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

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

任意类型 Mixedany

//@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语言规范与基本应用

任何一种JavaScript运行环境都支持。功能更为强大,生态也更健全、更完善。

Typescript是JavaScript的超集。

Typescript类型系统FLOW静态检查基本规范

微软自研的开发工具对Typescript支持特别好。

Typescript(渐进式)–前端领域中的第二语言。

Typescript缺点:

  • 语言本身多了很多概念
  • 项目初期,Typescript会增加一些成本

使用Typescript之前要先安装依赖。

标准库就是内置对象所对应的声明。

显示中文错误信息:yarn tsc --locale zh-CN,vs-code也可以设置locale为中文

Typescript作用域

我们可以用立即执行函数/export导出模块来创建一个单独作用域。

//立即执行函数
(function () {
    const a = 9
})()
//模块导出
export aa = {
    a: 23
}

Typescript原始类型

//原始数据类型
const a: string = 'foo'
const b: number = 100  //NaN/Infinity
const c: boolean = true  //false
const d: boolean = null
const e: void = undefined
const f: null = null
const g: undefined = undefined
const h: symbol = Symbol()

Typescript Object类型

并不单指普通的对象类型,而是泛指所有的非原始类型:对象、数组、函数。

//Object类型
const aa: object = function () { }  //[]//{}
const obj: { foo: number, bar: string } = { foo: 123, bar: 'aaa' }

更专业的方式是使用接口。

Typescript数组类型

有两种定义方式:

  • 使用Array泛型
  • 使用元素类型+[]
//数组类型
const arr: Array<number> = [1, 2, 3]
const arr1: number[] = [1, 2, 3]

Typescript元组类型(turple)

是一种特殊的数据结构,其实元组就是一个明确元素数量以及每个元素类型的数组,各个元素的类型不必要完全相同。定义方式:字面量方式

//元组类型
//元组(tuple)
export { }  //确保跟其他示例没有成员冲突
const tuple: [number, string] = [10, 'rock']
console.log(tuple[0]);  //10
console.log(tuple[1]);  //rock
//解构赋值
const [num, age] = tuple
Object.entries({
    foo: 123,
    zar: 432
})

Typescript枚举类型(enum)

enum Status {
    Draft = 'aaa',
    Unpulished = 'bbb',
    Published = 'ccc'
}

如果确认代码中不会使用索引器去访问枚举,就可以使用常量枚举。

//常量枚举
const post = {
    title: 'Hello',
    content: 'TypeScript',
    status: 'ok'
}

枚举类型会入侵到我们运行时的代码,它会影响到我们编译后的结果。我们在TypeScript中使用的大多数类型,它在经过编译转换后,最终都会被移除掉,因为它只是为了我们在编译过程中做类型检查,但枚举类型不会,它最终会变为一个双向键值对对象。

TypeScript函数类型

JavaScript中又两种函数定义方式:

函数声明

//函数声明方式
// function func1(a: number, b?: number): string {
// function func1(a: number, b: number=90): string {
function func1(a: number, ...rest: number[]): string {
    return 'hello'
}
func1(12, 34)
func1(30)

使用参数可选、参数默认值、剩余参数都需要放在参数列表的最后一个参数位置。

函数表达式

//函数表达式
const func2 = (a: number, b: number) => string = function (a: number, b: number): string {
    return 'func2'
}

TypeScript任意类型

因为any是弱类型,也是动态类型,所以TypeScript不会对any做类型检查。所以它存在类型安全问题,我们不要轻易去使用它。

function stringify(value: any) {
    return JSON.stringify(value)
}
stringify('string')
stringify(123)
stringify(true)
let foo: any = 'string'
foo = 100
foo.bar()

隐式类型判断

如果我们没有通过类型注解去标注一个变量,TypeScript会根据这个变量的使用情况去推断这个变量的类型。

//隐式类型推断
let age = 10 //number
// age = 'aaa'
let foo;
foo = 45
foo = 'aaa'

虽然定义变量时如果不给它指定类型,也不给初始值,TypeScript会自动帮他注解为any类型,但还是建议定义时就注明类型。

TypeScript类型断言

在某些特殊情况下,TypeScript无法去推断一个变量的类型,而我们作为开发者,我们根据代码的使用情况,我们是会明确知道这个变量到底是什么类型的。类型断言的方式:

  • 使用as关键字
  • 在变量前面使用<>(JSX中不能使用)
const nums = [12, 34, 56]
const res = nums.find(i => i > 10)
//断言方式一--as关键字
const num1 = res as number
//断言方式二---泛型
const num2 = <number>res

类型断言并不是类型转换,类型转换是代码在运行时的概念,而类型断言是代码在编译时的概念。当代码编译过后,断言也就不存在了。

TypeScript接口(Interface)

一种规范或者一种契约。它可以用来去约定对象的结构。去使用一个接口,就必须去遵守它所有的约定。

interface Post {
    title: string
    content: string
}
function printPost(post: Post) {
    console.log(post.title);
    console.log(post.content);
}
printPost({
    title: 'hello',
    content: 'welcome'
})
//hello
//welcome

TypeScript中的接口只是为了我们有结构的数据,去做类型约束的,在实际运行阶段,它并没有任何意义。

  • 可选成员
  • 只读成员
  • 动态成员
interface Post {
    title: string
    subtitle?: string   //可选成员
    content: string
    readonly summary: string  //只读成员
}

TypeScript类(class)

类的特征:描述一类具体事物的抽象特征。

类可以用来描述一类具体对象的抽象成员。

ES6以前,JavaScript都是通过函数+原型模拟实现类。ES6开始,JavaScript中有了专门的class。

TypeScript增强了class的相关语法。

class Person {
    name: string
    age: number
    constructor(name: string, age: number) {
        this.name = name
        this.age = age
    }
    sayHi(msg: string): void {
        console.log((`I am ${this.name}, ${msg}`));
    }
}

类的访问修饰符(默认是public修饰符)

class Person {
  public name: string // = 'init name'
  private age: number
  protected gender: boolean
  constructor (name: string, age: number) {
    this.name = name
    this.age = age
    this.gender = true
  }
  sayHi (msg: string): void {
    console.log(`I am ${this.name}, ${msg}`)
    console.log(this.age)
  }
}
class Student extends Person {
  private constructor (name: string, age: number) {
    super(name, age)
    console.log(this.gender)
  }
  static create (name: string, age: number) {
    return new Student(name, age)
  }
}

const tom = new Person('tom', 18)
console.log(tom.name)
// console.log(tom.age)
// console.log(tom.gender)
const jack = Student.create('jack', 18)

类的只读属性readonly

protected readonly gender:boolean

类与接口

接口就是把共同的特征封装起来。

interface EatAndRun {
    eat(food: string): void
    run(distance: number): void
}
class Person implements EatAndRun {
    eat(food: string): void {
        console.log(`美美的吃:${food}`);
    }
    run(distance: number) {
        console.log(`直立行走:${distance}`);
    }
}
class Animal implements EatAndRun {
    eat(food: string): void {
        console.log(`美美的吃:${food}`);
    }
    run(distance: number) {
        console.log(`直立行走:${distance}`);
    }
}

一个接口只约束一个能力,一个类型去实现多个接口。

interface Eat {
    eat(food: string): void
}
interface Run {
    run(distance: number): void
}
class Person implements Eat, Run {
    eat(food: string): void {
        console.log(`美美的吃:${food}`);
    }
    run(distance: number) {
        console.log(`直立行走:${distance}`);
    }
}
class Animal implements Eat, Run {
    eat(food: string): void {
        console.log(`美美的吃:${food}`);
    }
    run(distance: number) {
        console.log(`直立行走:${distance}`);
    }
}

TypeScript抽象类

抽象类与接口有点类似,也可以用来去约束子类中必须拥有某个成员。

但是抽象类可以包含一些具体的实现,但是接口只是成员的抽象,不包含具体的实现。

抽象类不能用new去实例了,只能去继承。

abstract class Animal {
    eat(food: string): void {
        console.log(`咕噜咕噜吃:${food}`);
    }
    abstract run(distance: number): void
}
class Dog extends Animal {
    run(distance: number): void {
        console.log(`四肢爬行:${distance}`);
    }
}
const d = new Dog()
d.eat('肉')
d.run(200)

TypeScript泛型

泛型:我们在定义函数、接口或类时,没有指定具体的类型,等到使用时再去指定具体类型的特征。

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

TypeScript类型声明

一个成员在定义时没有声明类型,在使用时单独为它做出明确声明。

import { camelCase } from 'lodash'
import qs from 'query-string'
qs.parse('?key=value&key2=value2')
declare function camelCase(input: string): string
const res = camelCase('hello')

以上就是Typescript类型系统FLOW静态检查基本规范的详细内容!


Tags in this post...

Javascript 相关文章推荐
高效的获取当前元素是父元素的第几个子元素
Oct 15 Javascript
jQuery+css实现百度百科的页面导航效果
Dec 16 Javascript
Node.js的包详细介绍
Jan 14 Javascript
仅30行代码实现Javascript中的MVC
Feb 15 Javascript
JavaScript 实现的checkbox经典实例分享
Oct 16 Javascript
JS正则替换去空格的方法
Mar 24 Javascript
jQuery中each循环的跳出和结束实例
Aug 16 jQuery
Webpack path与publicPath的区别详解
May 03 Javascript
javascript获取元素的计算样式
May 24 Javascript
Vue 动态路由的实现及 Springsecurity 按钮级别的权限控制
Sep 05 Javascript
vue+vant实现商品列表批量倒计时功能
Jan 13 Javascript
Element-ui upload上传文件限制的解决方法
Jan 22 Javascript
Web应用开发TypeScript使用详解
May 25 #Javascript
vue使用element-ui按需引入
May 20 #Vue.js
vue/cli 配置动态代理无需重启服务的方法
May 20 #Vue.js
Vue ECharts实现机舱座位选择展示功能
May 15 #Vue.js
Vue组件化(ref,props, mixin,.插件)详解
vue postcss-px2rem 自适应布局
May 15 #Vue.js
JS中forEach()、map()、every()、some()和filter()的用法
May 11 #Javascript
You might like
php模拟asp中的XmlHttpRequest实现http请求的代码
2011/03/24 PHP
PHP的异常处理类Exception的使用及说明
2012/06/13 PHP
php文件操作相关类实例
2015/06/18 PHP
Laravel搭建后台登录系统步骤详解
2016/07/26 PHP
PHPstorm快捷键(分享)
2017/07/17 PHP
跨浏览器开发经验总结(四) 怎么写入剪贴板
2010/05/13 Javascript
基于Jquery的回车成tab焦点切换效果代码(Enter To Tab )
2010/11/14 Javascript
javascript下拉列表中显示树形菜单的实现方法
2015/11/17 Javascript
js 模仿锚点定位的实现方法
2016/11/19 Javascript
关于TypeScript中import JSON的正确姿势详解
2017/07/25 Javascript
pm2启动ssr失败的解决方法
2019/06/29 Javascript
Vue项目中使用WebUploader实现文件上传的方法
2019/07/21 Javascript
原生js实现可兼容PC和移动端的拖动滑块功能详解【测试可用】
2019/08/15 Javascript
python基础教程之对象和类的实际运用
2014/08/29 Python
Python实现队列的方法
2015/05/26 Python
Python使用Redis实现作业调度系统(超简单)
2016/03/22 Python
python dict.get()和dict['key']的区别详解
2016/06/30 Python
python3使用SMTP发送简单文本邮件
2018/06/19 Python
python 循环读取txt文档 并转换成csv的方法
2018/10/26 Python
python实现简单的单变量线性回归方法
2018/11/08 Python
Python中__repr__和__str__区别详解
2019/11/07 Python
Python3以GitHub为例来实现模拟登录和爬取的实例讲解
2020/07/30 Python
在C中是否有模拟继承等面向对象程序设计特性的好方法
2012/05/22 面试题
销售员自我评价怎么写
2013/09/19 职场文书
外贸主管求职简历的自我评价
2013/10/23 职场文书
岗位职责的定义
2013/11/10 职场文书
应届生会计求职信
2013/11/11 职场文书
计算机专业职业生涯规划范文
2014/01/19 职场文书
酒店中秋节活动方案
2014/01/31 职场文书
擅自离岗检讨书
2014/02/11 职场文书
2014年小学生教师节演讲稿范文
2014/09/10 职场文书
2015年中学团委工作总结
2015/07/22 职场文书
初中生活随笔
2015/08/15 职场文书
运动会班级口号霸气押韵
2015/12/24 职场文书
煤矿安全生产管理协议书
2016/03/22 职场文书
浅谈Golang 切片(slice)扩容机制的原理
2021/06/09 Golang