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 相关文章推荐
javascript下arguments,caller,callee,call,apply示例及理解
Dec 24 Javascript
Node.js 条形码识别程序构建思路详解
Feb 14 Javascript
jQuery EasyUI中DataGird动态生成列的方法
Apr 05 Javascript
Treegrid的动态加载实例代码
Apr 29 Javascript
利用Node.js了解与测量HTTP所花费的时间详解
Sep 22 Javascript
javaScript强制保留两位小数的输入数校验和小数保留问题
May 09 Javascript
解决使用bootstrap的dropdown部件时报错:error:Bootstrap dropdown require Popper.js问题
Aug 30 Javascript
js神秘的电报密码 哈弗曼编码实现
Sep 10 Javascript
微信小程序实现单个卡片左滑显示按钮并防止上下滑动干扰功能
Dec 06 Javascript
微信小程序canvas实现签名功能
Jan 19 Javascript
JS中锚点链接点击平滑滚动并自由调整到顶部位置
Feb 06 Javascript
浅谈TypeScript 索引签名的理解
Oct 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
drupal 代码实现URL重写
2011/05/04 PHP
PHP框架Laravel插件Pagination实现自定义分页
2020/04/22 PHP
ThinkPHP实现登录退出功能
2017/06/29 PHP
如何利用PHP实现上传图片功能详解
2020/09/24 PHP
JavaScript中的排序算法代码
2011/02/22 Javascript
非html5实现js版弹球游戏示例代码
2013/09/22 Javascript
浅析XMLHttpRequest的缓存问题
2013/12/13 Javascript
原生js封装的一些jquery方法(详解)
2016/09/20 Javascript
Angular表单验证实例详解
2016/10/20 Javascript
javascript输出AscII码扩展集中的字符方法
2016/12/26 Javascript
jQuery的ajax中使用FormData实现页面无刷新上传功能
2017/01/16 Javascript
微信小程序开发之相册选择和拍照详解及实例代码
2017/02/22 Javascript
javascript实现二叉树遍历的代码
2017/06/08 Javascript
浅谈Vuejs Prop基本用法
2017/08/17 Javascript
vue-cli2.x项目优化之引入本地静态库文件的方法
2018/06/19 Javascript
jQuery实现参数自定义的文字跑马灯效果
2018/08/15 jQuery
Vue CLI3移动端适配(px2rem或postcss-plugin-px2rem)
2020/04/27 Javascript
python操作MySQL数据库具体方法
2013/10/28 Python
Python多线程编程(五):死锁的形成
2015/04/05 Python
详解Python中用于计算指数的exp()方法
2015/05/14 Python
Python 搭建Web站点之Web服务器与Web框架
2016/11/06 Python
TensorFlow深度学习之卷积神经网络CNN
2018/03/09 Python
详解Django中间件执行顺序
2018/07/16 Python
浅谈Python中os模块及shutil模块的常规操作
2020/04/03 Python
HTML5重塑Web世界它将如何改变互联网
2012/12/17 HTML / CSS
HTML5+CSS3应用详解
2014/02/24 HTML / CSS
Anya Hindmarch官网:奢侈设计师手袋及配饰
2018/11/15 全球购物
澳大利亚在线消费电子产品商店:TobyDeals
2020/01/05 全球购物
香奈儿美国官网:CHANEL美国
2020/05/20 全球购物
环保倡议书
2014/04/14 职场文书
岗位职责说明书
2014/05/07 职场文书
培训研修方案
2014/06/06 职场文书
代领毕业证委托书
2014/08/02 职场文书
群众路线教育实践活动整改方案(个人版)
2014/10/25 职场文书
2014年企业团支部工作总结
2014/12/10 职场文书
微信小程序 WeUI扩展组件库的入门教程
2022/04/21 Javascript