强类型与弱类型(类型安全)
- 强类型:语言层面限制函数的实参类型必须与形参类型相同。如Java语言
- 弱类型:语言层面不会限制函数的实参类型与形参类型一定要相同,如JavaScript
强类型中不允许有任意的隐式类型转换,而弱类型是允许的 强类型语言在编译阶段就能报类型不符合要求的错误
静态类型与动态类型(类型检查)
- 静态类型:
- 一个变量声明时它的类型就是明确的。
- 变量声明后,类型不允许修改。
- 动态类型:
- 变量在运行时才能确定类型。
- 变量的类型可以发生变化。
JavaScript类型系统特征
- JavaScript是弱类型且是动态类型的语言,比较任性,缺失类型系统的可靠性。
- 这是历史遗留的问题,没有编译环节,早期这种模式是比较有优势的。
- 但现如今JavaScript被大规模的应用,这种模式成了劣势。
弱类型的劣势
- 必须等运行时候才能发现类型的异常,开发测试时候不容易发现类型的问题。
- 多人协同开发的时候出异常概率更大。
- 类型不明确会导致函数功能异常。
- 类型随意转换会带来隐藏的bug。
强类型的优势
- 错误更早暴露。
- 代码更智能,编码更准确。
- 重构更牢靠。
- 减少不必要的类型判断。省去了手动判断类型的操作。
Flow
JavaScript的类型检查器,FaceBook开源的
// 类型注解,可以使用babel编译去除注解
// @flow 用于flow命令检查
function sum(a: number, b: number){
return a + b
}
// yarn add flow-bin --dev开发依赖
// flow init 初始化.flowconfig文件
// flow 开始类型检查
使用工具来移除注解(flow)
- flow-remove-types: flow-remove-types src -d dist.
- babel: 安装@babel/core @babel/cli @babel/preset-flow。然后添加.babelrc配置文件。运行babel src -d dist命令。
// .babelrc文件内容
{
"presets": ["@babel/preset-flow"]
}
Flow开发工具插件
- vscode插件:Flow Language Support 保存文件后才会出现错误提示。
- flow官网中编辑器支持的情况
Flow 类型推断
- 根据代码使用情况,推断代码中的类型,提示错误。
Flow 类型注解
// 函数参数的标注
function square (n: number) {
return n * n
}
// 变量的类型标注
let num: number = 100
// 函数返回值类型的标注,如果函数没有返回值 标注void
function foo (): number{
return 100
}
Flow 原始类型
JavaScript中原始数据类型: String Number Boolean Null undefind Symbol
const a: string = 'foo'
const b: number = 100 // NaN // Infinity
const c: boolean = true
const d: null = null
const e: void = undefined
cosnt f: symbol = Symbol()
数组类型
// 需要使用泛型标注数组每一位是什么类型的值
const arr1: Array<String> = ['foo','str']
const arr2: number[] = [1, 2, 3]
// 表示固定长度数组 也称元组
const foo: [string, number] = ['foo', 100]
对象类型
const obj1: { foo: string, bar: number } = {
foo: "foo",
bar: 12
}
// 可选参数
const obj1: { foo?: string, bar: number } = {
bar: 12
}
// 当前对象允许添加任意类型键值,但是键值必须是字符串类型
const obj: { [string]: string } = {}
obj.key1 = "foo"
函数类型
function foo(callback: (string, number) => void) {
callback()
}
foo(function("str", 100){
})
特殊类型
// 直接标注字面量 通常配合联合类型使用
const a: 'foo' = 'foo'
const type: 'success' | 'warning' | 'danger' = 'success'
const b: string | number = "123" //123
type StringOrNumber = string|number
const b: StringOrNumber = 'string'
// maybe 有可能
const gender: ?number = null // undefined // 123
const gender: number| null | undefined
任意类型
- mixed 强类型
- Any 弱类型
function passMixed (value: mixed) {
// 如果进行了多种类型的运算或者调用了多种类型的方法 会报警告
}
function passAny (value: any){
//
}
Flow 运行环境API
浏览器环境的DOM,BOM。node中的fs等
const element: HTMLELement | null = document.getElementById('app')
TypeScript
JavaScript的超集
- 包含了JavaScript,类型系统和ES6+。
- 能编译到低版本浏览器中运行,最低编译到ES3。
- 功能更强大,生态也更健全,更完善。
- Angular/Vuejs3.0
缺点:
- 语言本身多了很多概念,例如:枚举,泛型,接口等概念。不过好在TS也是渐进式的,上手快进阶快。
- 项目初期,TypeScript会增加一些成本,比如需要编写很多类型。但对于长期维护的大型项目,带来的优势远大于这些劣势。
基础用法
// yarn add typescript --dev
// tsc命令 帮助编译ts代码
// TypeScript文件扩展名默认是.ts
// 类型标注与Flow类似
const hello = (name: string) => {
console.log(`hello,${name}`)
}
配置文件
- 编译工程的时候使用 ``` tsc —init // 初始化tsconfig.json 配置文件
CompilerOptions中的常用属性: target属性:表示编译后的ES版本 module属性:表示编译完遵循什么样的模块化规范 outDir属性:表示编译输出的目录 rootDir属性:表示的是TS源代码的文件夹 sourceMap属性: 表示开启源代码映射,可以在编译后调试TS源代码 strict:开启严格检查模式,需要明确指定类型
直接运行tsc才会根据配置文件编译
<a name="c410d590"></a>
## 原始数据类型的标注
```javascript
const a: string = 'foobar'
const b: number = 100
const c: boolean = true
// 上面三个与flow不同的是 这些标注允许值为空(null或者undefined,关闭严格模式才允许)
const d: void = undefined
const e: null = null
const f: undefined = undefined
const g: symbol = Symbol() // 需要将tsconfig.js中target修改为es2015 或者在lib中增加上["ES2015", "DOM"]
TS显示中文错误消息
- tsc —locale zh-CN
- VSCode中配置文件里面搜索typescript locale将Locale设置为zh-CN
TS中作用域的问题
- 可使用立即执行函数
- 或者在文件中使用 export {}
Object类型
泛指所有非原始类型:对象,数组,函数
const foo: object = function () {} || [] || {}
const obj: { foo: number, bar: string } = { foo: 123, bar: 'string' } //对象标注最好用接口形式
数组类型
const arr1: Array<number> = [1, 2, 3]
const arr2: number[] = [1, 2, 3]
元组类型
const tuple: [number, string] = [12, 'azx']
// 一般用来标注函数返回值
枚举类型
const enum PostStatus {
Draft = 0,
Unpublished = 1,
Published = 2
}
// 如果枚举不指定,就会从0开始累加或者从第一位值开始累加
const post = {
title: "aaa",
status: PostStatus.Draft
}
函数类型
// 函数声明
function func1 (a: number, b?: number, ...rest: number[]): string {
return 'func1'
}
// 函数表达式
const func2: (a: number, b: number) => string = function (a: number, b: number): string {
}
任意类型
function stringify (value: any) {
return JSON.stringify(value)
}
// any 类型是动态类型的
隐式类型推断
let age = 18
//age 会被推断为number 如果推断不了会解析为any
类型断言
// 相当于明确告诉TS是什么类型的
const num1 = res as number
const num2 = <number>res // 如果jsx中使用就会有冲突
接口
规范,约定对象的结构
interface Post{
title: string
content: string
subtitle?: string// 可有可无的
readonnly summary: string // 只读成员
}
function printPost (post: Post) {
console.log(post.title)
console.log(post.content)
}
printPost({
title:"JavaScript高级程序设计"
content: "A JavaScript Book"
})
// 动态成员
interface Cache {
[prop: string]: string // 键值是string类型
}
类(class)
用来描述一类具体对象的抽象成员,TS增强了class的相关语法
class Person {
name: string = 'init name'
private age: number = 18
protected readonly gender: boolean //只读属性
constructor(name: string, age: number, gender: boolean) {
this.name = name
this.age = age
this.gender = gender
}
sayHi (msg: string): void {
console.log(`I am ${this.name}, ${msg}`)
}
}
// 类的成员需要声明并且标注,而且构造函数中也要赋值
// 可使用修饰符来修饰成员变量,越来越像Java了 public private protected
// protected只允许在子类中访问成员
// 构造函数也能被修饰,这样只能使用静态方法调用构造函数
- 类与接口 ```javascript interface EatAndRun { eat (food: string): void run (distance: number): void }
class Person implements EatAndRun { eat(food){ console.log(food) } run(distance) { console.log(distance) } }
class Animal implements EatAndRun { eat(food){ console.log(food) } run(distance) { console.log(distance) } } // 真·越来越像Java 不过Java中的接口可以约定方法,实现类必须实现方法 // 一个接口约定一种方法 类型 用类实现多个接口
- 抽象类
```javascript
abstract class Animal {
abstract run (distance: number):void
}
// 子类继承的时候实现这个抽象方法
// 真·真·越来越像Java
泛型
声明函数时不指定类型,调用的时候才指定类型
function createNumberArray (length: number, value: number): number[] {
const arr = Array<number>(length).fill(value)
return arr
}
function createArray<T> (length: number, value: T): T[] {
const arr = Array<T>(length).fill(value)
return arr
}
const res = createNumberArray(3, 100) // [100, 100, 100]
const res1 = createArray<string>(3, "123")
类型声明
第三方库不一定有类型声明文件
// 比如lodash
declare function camelCase(input: string): string
// 或者安装lodash的类型声明文件 @types/lodash