为什么要学习 TypeScript
前端老法师应该都晓得,一路走来js有太多不欠缺的中央;呃,它是弱类型语言,它是解释型脚本,它入门其实很简略但深刻挺难。想要晓得为什么学习 TypeScript,那么咱们首先要学习下什么是强类型、弱类型、动态类型、动静类型、类型零碎。
强类型与弱类型(类型平安)
强类型,形参和实参的类型必须保持一致
强类型,不容许随便的隐式类型转换,而弱类型是容许的
弱类型的问题
缺失了类型零碎的可靠性:
- 一些类型异样要等到运行时能力发现
- 类型不明确造成函数性能的扭转
- 对象索引器的谬误用法
// 1. 异样须要等到运行时能力发现const obj = {}// obj.foo()setTimeout(() => { obj.foo()}, 1000000)// =========================================// 2. 函数性能可能产生扭转function sum (a, b) { return a + b}console.log(sum(100, 100))console.log(sum(100, '100'))// =========================================// 3. 对象索引器的谬误用法const obj = {}obj[true] = 100 // 属性名会主动转换为字符串console.log(obj['true'])
强类型的劣势
- 更早的裸露谬误,可提前在语法阶段
- 代码编写更智能,编码更精确(智能提醒,开发工具能更无效的推断)
- 重构更可靠
- 缩小了代码层面的不必要的类型判断
// 1. 强类型代码谬误更早裸露// 2. 强类型代码更智能,编码更精确function render (element) { element.className = 'container' element.innerHtml = 'hello world'}// =================================// 3. 重构更牢靠const util = { aaa: () => { console.log('util func') }}// =================================// 4. 缩小了代码层面的不必要的类型判断function sum (a, b) { if (typeof a !== 'number' || typeof b !== 'number') { throw new TypeError('arguments must be a number') } return a + b}
动态类型与动静类型(类型查看)
- 动态类型:一个变量申明时它的类型就是明确的,申明过后不容许在批改
- 动静类型:运行阶段才明确变量的类型,而且能够批改(或者说变量没有类型,变量寄存的值有类型)
Flow工具:javascript的类型查看器
官网:https://flow.org/en/docs/types/
手册:https://www.saltycrane.com/ch...
注意事项:
1、Flow工具能够在代码编写过后查看类型谬误;
2、通常将源码写在src目录,编译后移除类型注解到dist目录用于生产环境;
装置/初始化Flow工具
1、装置Flow工具:yarn add flow-bin --dev(装置Flow)
2、初始化Flow工具:yarn flow init(初始化Flow,生成.flowconfig文件)
如何应用Flow工具
1、在js文件顶部增加一行:@flow
2、在命令行执行命令:yarn flow
// @flowfunction sum (a: number, b: number) { return a + b}sum(100, 100)// sum('100', '100')// sum('100', 100)
Flow工具移除类型注解
1、办法一:执行命令:yarn flow-remove-types ./ -d dist
2、办法二:应用babel插件来转换源码,须要装置3个babel插件,而后应用babel命令:
@babel/core
@babel/cli
@babel/preset-flow
.babelrc文件
{ "presets": ["@babel/preset-flow"]}
3、办法二:在命令行应用babel命令:yarn babel src -d dist
vscode 插件:间接代码编写页面展现语法错误
插件:Flow Language Support,能够在js文件保留后主动查看谬误
TypeScript语言的特点
Typescript 特点
Typescript = (js、es6+、类型零碎) => 编译成js
Typescript 是js的超集
Typescript 性能更弱小,生态更健全、欠缺
Angular、Vue3.0应用TS开发
属于渐进式,边学边写
Typescript 毛病
多了很多概念:类型、泛型、枚举等
小型我的项目,我的项目初期 Typescript 会减少一些老本
TypeScript配置文件
装置ts
yarn add typescript --dev
编译ts
yarn tsc index.ts
初始化ts配置项:生成 tsconfig.json 文件
yarn tsc --init
tsconfig.json文件只有在运行整个我的项目的时候能力失效:yarn tsc
"target": "es5", // 编译成es版本: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'.
"module": "commonjs", // 应用哪种模块加载形式:'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'.
"sourceMap": true, // 源码映射,不便调试
"outDir": "./", // 代码输入目录
"rootDir": "./", // 源码输入目录
TS原始类型
/** * 根底数据类型的应用 */const a:string = "string"const b:number = 100 //NaN Infinityconst c:boolean = true //false//非严格模式下string、number、boolean都能够为空//严格模式下会报错const t:string = null//非严格模式下能够是null、undefined//严格模式下只能是undefinedconst d:void = undefinedconst e:null = nullconst f:undefined = undefined//默认状况下应用Symbol()会报错//symbol类型只能在es2015,es6+中能力应用;Promise也有雷同问题,也是es2015中引入//能够在tsconfig.json配置文件lib中增加ES2015、DOM(解决console报错问题)//"lib": ["ES2015","DOM"], const g:symbol = Symbol()
TS强制显示中文的谬误音讯
命令行显示中文:
yarn tsc --locale zh-CN
vscode配置显示中文:
setting 外面搜寻:typescript local,第一个选项抉择:zh-CN
TS Object类型,泛指对象、函数、数组
- Object类型,指除了原始类型外的其它类型
- 对象属性类型限度,能够应用相似对象字面量的形式,但最好用接口
const foo: object = function(){}const obj: {a: number, b: string} = {a: 1, b: 's'}
TS数组类型
数组类型的申明
const arr1: Array<number> = [1,2,3]const arr2: number[] = [1,2,3]
TS元组类型
在数组中应用不同类型的元素
const triple: [string, number] = ['s',18]// const name: string = triple[0]// const age: number = triple[1]const [name, age] = triple
TS枚举类型,enum
通常用于示意不同的状态,它有两个益处:
1、能够给一组数值去上一个更好的名字
2、只会存在几个固定的值
// 规范的数字枚举,能够不赋值从0开始计数,前面主动+1enum PostStatus { Draft = 0, Unpublished = 1, Published = 2}// 数字枚举,枚举值主动基于前一个值自增+1enum PostStatus { Draft = 6, Unpublished, // => 7 Published // => 8}// 字符串枚举,用的不多enum PostStatus { Draft = 'aaa', Unpublished = 'bbb', Published = 'ccc'}// const常量枚举,不会侵入编译后果// 侵入编译后果,即编译后为双向键值对,也能够通过索引拜访值:PostStatus[0] // => Draftconst enum PostStatus { Draft, Unpublished, Published}const post = { title: 'Hello TypeScript', content: 'TypeScript is a typed superset of JavaScript.', status: PostStatus.Draft // 3 // 1 // 0}
TS函数类型
函数申明
// 形参和实参的个数必须统一// 应用 ? 增加可选参数// 应用 = 增加默认参数// 可选参数、默认参数都须要放在最初// ...reset放到最初,承受任意个数的参数function func1 (a: number, b: number = 10, ...rest: number[]): string { return 'func1'}func1(100, 200)func1(100)func1(100, 200, 300)
函数表达式
// 一般函数表达式,TS能够推断进去返回值类型const func2 = function (a: number, b: number): string { return 'func2'}// 函数作为参数,应用箭头函数// const func2 = (a, b) => "func2"const func2: (a: number, b: number) => string = function (a: number, b: number): string { return 'func2'}
TS任意类型:any,不平安
TS隐式类型推断
let age = 18 // number => 推断为number类型// age = 'string' //报错,曾经推断为number类型let foo // 推断为any类型foo = 100foo = 'string'
TS类型断言
// 假设这个 nums 来自一个明确的接口const nums = [110, 120, 119, 112]const res = nums.find(i => i > 0)// const square = res * resconst num1 = res as number // 办法一:asconst num2 = <number>res // 办法二:JSX 下不能应用
TS接口,interface
约定对象中有哪些成员,以及成员的类型
接口束缚的成员,对象中就必须要有这些成员
interface Post { title: string content: string subtitle?: string // 可选成员,可有可无 readonly summary: string // 只读成员,初始化后不能在批改}const hello: Post = { title: 'Hello TypeScript', content: 'A javascript superset', summary: 'A javascript'}// hello.summary = 'other'// ----------------------------------interface Cache { [prop: string]: string // prop为动静属性,prop为属性名(自定)}const cache: Cache = {}cache.foo = 'value1'cache.bar = 'value2'
TS类
根本应用继承了ES6中class的用法,但须要明确类中的成员有哪些以及类型
class Person { name: string // = 'init name' 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
private 不容许内部拜访,只容许在类的外部拜访成员
protected 不容许内部拜访,只容许在子类中拜访成员
在构造函数前也能应用private,只能通过static动态函数去生城实例
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)
类的只读属性
属性只能在申明时或者构造函数中初始化,两者选其一
class Person { public name: string // = 'init name' private age: number // 只读成员 protected readonly 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) }}const tom = new Person('tom', 18)console.log(tom.name)// tom.gender = false
类与接口
接口能够束缚类中的成员函数
一个接口尽量只实现一个性能
// 接口能够束缚类中的成员函数// 参数、返回值interface Eat { eat (food: string): void}interface Run { run (distance: number): void}// implements关键字// 束缚过后类中必须要有接口中的成员,否则报错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}`) }}
TS抽象类(能够参考C++的了解)
束缚子类中必须要有某个成员(相似于接口)
不蕴含成员的具体实现
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(100)
TS泛型
不指定类型,调用的时候再指定具体的类型
以下实例中,T的类型能够依据状况指定具体的类型,但所有T应该保持一致
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 = createNumberArray(3, 100)// res => [100, 100, 100]const res = createArray<string>(3, 'foo')
TS函数申明,类型申明模块
- 在ts中援用第三方模块时,如果不存在类型申明,能够尝试装置一个类型申明模块
- 例如:lodash,能够装置一个:@types/lodash
- 如果没有类型申明模块,只能应用declare 去申明模块类型
- 目前有些模块曾经集成了类型申明文件(没有报错就示意有?例如:qs模块)
import { camelCase } from 'lodash'import qs from 'query-string'// qs外部曾经集成了类型申明qs.parse('?key=value&key2=value2')// declare function camelCase (input: string): stringconst res = camelCase('hello typed')
TS断言推断等简写
- 变量! => 变量结尾加上感叹号,有值断言
elm = oldVnode.elm!// ===>if(oldVnode.elm) elm = oldVnode.elmelse return
- 变量 as 类型 => 变量前面 as 某种类型,类型断言
- 变量? => 变量结尾加上问号,有值判断
let init = hook?.init//===>let init = hook?hook.init:undefined
特地鸣谢:拉勾教育前端高薪训练营;