从类型安全的角度可以分为强类型与弱类型
从类型检查的角度可以分为静态类型与动态类型
javaScript就是典型的弱类型且动态类型语言,语言本身的类型系统是非常薄弱的,几乎没有任何的类型限制,及其灵活多变的,缺失了类型系统的可靠性
强类型语言不允许有任意的隐式类型转换,而弱类型语言则允许任意的数据类型转换
JavaScript 弱类型产生的问题
1. 异常需要等到运行时才能发现
const obj = {}
setTimeout(() => {
obj.foo()
}, 1000000)
2. 函数功能可能发生改变
function sum (a, b) {
return a + b
}
console.log(sum(100, 100)) // 200
console.log(sum(100, '100')) // 100100
3. 对象索引器的错误用法
const obj = {}
obj[true] = 100 // 属性名会自动转换为字符串
console.log(obj['true'])
强类型的优势
1. 强类型代码错误更早暴露
2. 强类型代码更智能,编码更准确
3. 重构更可靠
4. 减少了代码层面的不必要的类型判断
静态类型与动态类型
静态类型:一个变量声明时它的类型就是明确的,声明过后,类型不允许再修改
动态类型:运行阶段才能够明确变量类型,变量类型可随时发生变化。变量是没有类型的,变量中存放的值是有类型的
Flow javaScript 的类型检察器
// @flow 需要有这个标记才能检查到标注类型是否正确
// 安装flow yarn add flow-bin --dev
function sum (a: number, b: number) { // 类型注解
return a + b
}
sum(100, 100)
// sum('100', '100')
// sum('100', 100)
TypeScript
缺点一:语言本身多了很多概念,如接口、泛型、枚举,这些概念会增加学习成本,好在TypeScript属于渐进式,意思就是 即便我们什么类型都不知道,还是可以按照javascript语言的语法去编写代码,在了解过程当中学习到什么特性再使用
缺点二:项目初期会增加一些开发成本,因为在项目初期需要去编写很多类型声明
快速上手
安装,初始化项目
命令:yarn init --yes
yarn add typescript --dev 这个模块提供了一个tsc的命令,可编译ts文件,同时会去检验类型异常
yarn tsc '文件名'
配置文件
命令:yarn tsc --init 会生成一个tsconfig.json的文件
{
"compilerOptions": {
/* Visit https://aka.ms/tsconfig.json to read more about this file */
/* Basic Options */
// "incremental": true, /* Enable incremental compilation */
"target": "es5", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */
"module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */
// "lib": [], /* Specify library files to be included in the compilation. */
// "allowJs": true, /* Allow javascript files to be compiled. */
// "checkJs": true, /* Report errors in .js files. */
// "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */
// "declaration": true, /* Generates corresponding '.d.ts' file. */
// "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */
// "sourceMap": true, /* Generates corresponding '.map' file. */
// "outFile": "./", /* Concatenate and emit output to single file. */
"outDir": "dist", /* Redirect output structure to the directory. */
// "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
// "composite": true, /* Enable project compilation */
// "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */
// "removeComments": true, /* Do not emit comments to output. */
// "noEmit": true, /* Do not emit outputs. */
// "importHelpers": true, /* Import emit helpers from 'tslib'. */
// "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */
// "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */
/* Strict Type-Checking Options */
"strict": true, /* Enable all strict type-checking options. */
// "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */
// "strictNullChecks": true, /* Enable strict null checks. */
// "strictFunctionTypes": true, /* Enable strict checking of function types. */
// "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */
// "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */
// "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */
// "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */
/* Additional Checks */
// "noUnusedLocals": true, /* Report errors on unused locals. */
// "noUnusedParameters": true, /* Report errors on unused parameters. */
// "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */
// "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */
// "noUncheckedIndexedAccess": true, /* Include 'undefined' in index signature results */
/* Module Resolution Options */
// "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */
// "baseUrl": "./", /* Base directory to resolve non-absolute module names. */
// "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */
// "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */
// "typeRoots": [], /* List of folders to include type definitions from. */
// "types": [], /* Type declaration files to be included in compilation. */
// "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
"esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
// "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */
// "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
/* Source Map Options */
// "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */
// "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */
// "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */
// "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */
/* Experimental Options */
// "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */
// "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */
/* Advanced Options */
"skipLibCheck": true, /* Skip type checking of declaration files. */
"forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */
}
}
常用属性说明target // 编译后的语法outDir // 编译后文件目录rootDir // 源代码目录sourceMap // 开启源代码映射,方便调试strict // 开启严格模式,对于类型的检查会变得非常的严格
原始数据类型
// 原始数据类型
const a: string = 'foobar'
const b: number = 100 // NaN Infinity
const c: boolean = true // false
// 在非严格模式(strictNullChecks)下,
// string, number, boolean 都可以为空
// const d: string = null
// const d: number = null
// const d: boolean = null
const e: void = undefined
const f: null = null
const g: undefined = undefined
// Symbol 是 ES2015 标准中定义的成员,
// 使用它的前提是必须确保有对应的 ES2015 标准库引用
// 也就是 tsconfig.json 中的 lib 选项必须包含 ES2015
const h: symbol = Symbol()
// Promise
// const error: string = 100
作用域问题:在不同文件中定义了相同变量的问题
// 默认文件中的成员会作为全局成员
// 多个文件中有相同成员就会出现冲突
// const a = 123
// 解决办法1: IIFE 提供独立作用域
// (function () {
// const a = 123
// })()
// 解决办法2: 在当前文件使用 export,也就是把当前文件变成一个模块
// 模块有单独的作用域
const a = 123
export {}
Object类型
范指非原始类型,如对象、数组、函数
// Object 类型
export {} // 确保跟其它示例没有成员冲突
// object 类型是指除了原始类型以外的其它类型
const foo: object = function () {} // [] // {}
// 如果需要明确限制对象类型,则应该使用这种类型对象字面量的语法,或者是「接口」
// 赋值的类型结构应与声明的类型结构完全一致,不能多 也不能少
const obj: { foo: number, bar: string } = { foo: 123, bar: 'string' }
// 数组类型export {} // 确保跟其它示例没有成员冲突// 数组类型的两种表示方式const arr1: Array<number> = [1, 2, 3]const arr2: number[] = [1, 2, 3]// 案例 -----------------------// 如果是 JS,需要判断是不是每个成员都是数字// 使用 TS,类型有保障,不用添加类型判断function sum (...args: number[]) { return args.reduce((prev, current) => prev + current, 0)}sum(1, 2, 3) // => 6
// 枚举(Enum)
export {} // 确保跟其它示例没有成员冲突
// 用对象模拟枚举
// const PostStatus = {
// Draft: 0,
// Unpublished: 1,
// Published: 2
// }
// 标准的数字枚举
// enum PostStatus {
// Draft = 0,
// Unpublished = 1,
// Published = 2
// }
// 数字枚举,枚举值自动基于前一个值自增
// enum PostStatus {
// Draft = 6,
// Unpublished, // => 7
// Published // => 8
// }
// 字符串枚举
// enum PostStatus {
// Draft = 'aaa',
// Unpublished = 'bbb',
// Published = 'ccc'
// }
// 常量枚举,不会侵入编译结果
const enum PostStatus {
Draft,
Unpublished,
Published
}
const post = {
title: 'Hello TypeScript',
content: 'TypeScript is a typed superset of JavaScript.',
status: PostStatus.Draft // 3 // 1 // 0
}
// PostStatus[0] // => Draft
// 函数类型
// 函数的输入、输出的类型需保持一致,输入的参数个数也需要保持一直
export {} // 确保跟其它示例没有成员冲突
function func1 (a: number, b: number = 10, ...rest: number[]): string {
return 'func1'
}
func1(100, 200)
func1(100)
func1(100, 200, 300)
// 任意类型(弱类型)
// 语法上都不会报错
export {} // 确保跟其它示例没有成员冲突
function stringify (value: any) {
return JSON.stringify(value)
}
stringify('string')
stringify(100)
stringify(true)
let foo: any = 'string'
foo = 100
foo.bar()
// any 类型是不安全的
// 隐式类型推断
export {} // 确保跟其它示例没有成员冲突
let age = 18 // number
// age = 'string'
let foo // 此时foo为any类型
foo = 100
foo = 'string'
// 建议为每个变量添加明确的类型标注
// 类型断言
export {} // 确保跟其它示例没有成员冲突
// 假定这个 nums 来自一个明确的接口
const nums = [110, 120, 119, 112]
const res = nums.find(i => i > 0) // 此时res推断类型为number | undefield
// const square = res * res
const num1 = res as number // 断言,此处明确res为number类型
const num2 = <number>res // JSX 下不能使用