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 相关文章推荐
利用webqq协议使用python登录qq发消息源码参考
Apr 08 Javascript
Checbox的操作含已选、未选及判断代码
Nov 07 Javascript
用json方式实现在 js 中建立一个map
May 02 Javascript
js创建对象的区别示例介绍
Jul 24 Javascript
JavaScript常用脚本汇总(一)
Mar 04 Javascript
jQuery基于扩展简单实现倒计时功能的方法
May 14 Javascript
AngularJS基础 ng-keypress 指令简单示例
Aug 02 Javascript
微信公众号 摇一摇周边功能开发
Dec 08 Javascript
JavaScript自定义分页样式
Jan 17 Javascript
超级简易的JS计算器实例讲解(实现加减乘除)
Aug 08 Javascript
AngularJS通过ng-Img-Crop实现头像截取的示例
Aug 17 Javascript
react实现移动端下拉菜单的示例代码
Jan 16 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封装的图片(缩略图)处理类完整实例
2016/10/19 PHP
浅谈PHP匿名函数和闭包
2019/03/08 PHP
详解phpstorm2020最新破解方法
2020/09/17 PHP
Javascript 学习书 推荐
2009/06/13 Javascript
javascript-简单的计算器实现步骤分解(附图)
2013/05/30 Javascript
jquery validation验证身份证号,护照,电话号码,email(实例代码)
2013/11/06 Javascript
input链接页面、打开新网页等等的具体实现
2013/12/30 Javascript
无刷新预览所选择的图片示例代码
2014/04/02 Javascript
JS实现双击编辑可修改状态的方法
2015/08/14 Javascript
BootStrap Fileinput初始化时的一些参数
2016/12/30 Javascript
bootstrap导航栏、下拉菜单、表单的简单应用实例解析
2017/01/06 Javascript
Bootstrap导航简单实现代码
2017/03/06 Javascript
理解Koa2中的async&amp;await的用法
2018/02/05 Javascript
webpack+vuex+axios 跨域请求数据的示例代码
2018/03/06 Javascript
vue使用技巧及vue项目中遇到的问题
2018/06/04 Javascript
原生js实现form表单序列化的方法
2018/08/02 Javascript
微信小程序实现评论功能
2018/11/28 Javascript
vue-router跳转时打开新页面的两种方法
2019/07/29 Javascript
layui type2 通过url给iframe子页面传值的例子
2019/09/06 Javascript
在vue中实现给每个页面顶部设置title
2020/07/29 Javascript
js实现磁性吸附的示例
2020/10/26 Javascript
[01:25]2015国际邀请赛最佳短片奖——斧王《拆塔英雄:天赋异禀》
2015/09/22 DOTA
python解析json实例方法
2013/11/19 Python
Python shutil模块用法实例分析
2019/10/02 Python
Python编程快速上手——Excel到CSV的转换程序案例分析
2020/02/28 Python
使用Python爬虫爬取小红书完完整整的全过程
2021/01/19 Python
世界各地的旅游、观光和活动:Isango!
2019/10/29 全球购物
类和结构的区别
2012/08/15 面试题
Laravel中Kafka的使用详解
2021/03/24 PHP
室内设计专业个人的自我评价
2013/10/19 职场文书
幼儿教师国培感言
2014/02/19 职场文书
畜牧兽医本科生的自我评价
2014/03/03 职场文书
校长竞聘演讲稿
2014/05/16 职场文书
应届大专生自荐书
2014/06/16 职场文书
2015年端午节活动总结
2015/02/11 职场文书
《认识钟表》教学反思
2016/02/16 职场文书