乐趣区

关于前端:10分钟学会TypeScript总结TS的常用特性

为什么要学习 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

// @flow

function 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 Infinity

const c:boolean = true //false

// 非严格模式下 string、number、boolean 都能够为空
// 严格模式下会报错
const t:string = null

// 非严格模式下能够是 null、undefined
// 严格模式下只能是 undefined
const d:void = undefined
const e:null = null
const 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 开始计数,前面主动 +1
enum PostStatus {
  Draft = 0,
  Unpublished = 1,
  Published = 2
}

// 数字枚举,枚举值主动基于前一个值自增 +1
enum PostStatus {
  Draft = 6,
  Unpublished, // => 7
  Published // => 8
}

// 字符串枚举,用的不多
enum PostStatus {
  Draft = 'aaa',
  Unpublished = 'bbb',
  Published = 'ccc'
}

// const 常量枚举,不会侵入编译后果
// 侵入编译后果,即编译后为双向键值对,也能够通过索引拜访值:PostStatus[0] // => Draft
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
}

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 = 100

foo = 'string'

TS 类型断言

// 假设这个 nums 来自一个明确的接口
const nums = [110, 120, 119, 112]

const res = nums.find(i => i > 0)

// const square = res * res

const num1 = res as number // 办法一:as

const 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): string

const res = camelCase('hello typed')

TS 断言推断等简写

  • 变量! => 变量结尾加上感叹号,有值断言
elm = oldVnode.elm!
// ===>
if(oldVnode.elm)
  elm = oldVnode.elm
else 
  return
  • 变量 as 类型 => 变量前面 as 某种类型,类型断言
  • 变量? => 变量结尾加上问号,有值判断
let init = hook?.init
//===>
let init = hook?hook.init:undefined

特地鸣谢:拉勾教育前端高薪训练营;

退出移动版