TypeScript入门

概述

解决了JS类型问题。
在这里插入图片描述
强类型,语言层面限制函数的实参类型必须和形参类型相同。
在这里插入图片描述

弱类型就不限制,比如js。
在这里插入图片描述
js中所有的类型判断错误都是运行时的代码判断,强类型的在编译的时候就报错了。
在这里插入图片描述
例如python的变量是可以随时改变类型的。

类型系统 静态类型与动态类型

静态类型:声明的时候就是明确的而且是不能被改变的例如java,
动态类型:运行阶段才能明确类型,而且可以随时变化。
动态类型种变量没有类型,变量存放的值有类型。
总之就是是否能被类型转换,能就是动态,反之静态。
在这里插入图片描述

JavaScript 类型系统特征

js是脚本语言,没有编译环节。起初的JS只是写简单的应用,不需要设计成强类型。

弱类型的问题

1.只有在运行阶段才能发现代码问题,语法上是可行的
在这里插入图片描述
2.类型补确定的后果
在这里插入图片描述
3.对象属性名自动转换成字符串的特点
在这里插入图片描述

强类型的优势

1.错误更早暴露。
2.代码更智能,编码更准确(这就是为什么编辑器无法提示内部属性,因为无法判断是什么类型的)
3.重构更牢靠
4减少不必要的类型判断

Flow 概述

JS的类型检测器
在这里插入图片描述
编码阶段就可以知道是否错误。

Flow 快速上手

安装 yarn add flow-bin --dev
记得关闭JS的语法检查,不然报错
在这里插入图片描述
然后再 yarn flow init 不然会找不到执行文件
小插曲,执行yarn flow的时候报错了。原因是路径中文名,换成英文的就可以了。

总结

快速上手:
安装flow: yarn add flow-bin --dev
文件顶部添加注释标记: @flow
添加flow配置文件: yarn flow init
执行flow命令检对应文件: yarn flow
停止flow后台任务: yarn flow stop
编译移除注解
flow工具

Flow 编译移除注解

因为 node运行的话会报错,在运行的时候需要移除注解。不然报错。
安装flow提供的工具: yarn add flow-remove-types --dev
执行命令: yarn flow-remove-types . -d dist

2使用babel

安装babel提供的工具: yarn add @babel/core @babel/cli @babel/preset-flow
添加配置文件.babelrc {“presets”: ["@babel:preset-flow"]}
执行命令 yarn babel src -d dist 在dist中找到编译后的js文件
自动被移除了

在这里插入图片描述

Flow 开发工具插件

VScode插件商店 搜索 Flow Language Support 安装即可,保存之后才会重新检查。
在这里插入图片描述

Flow 类型推断

可以自动判断类型。
在这里插入图片描述

Flow 类型注解

变量和返回值也可以,没有返回值可以用 void代替

在这里插入图片描述

Flow 原始类型

/**
 * 原始类型
 *
 * @flow
 */

const a: string = 'foobar'

const b: number = Infinity // NaN // 100

const c: boolean = false // true

const d: null = null

const e: void = undefined  //undefined用void表示

const f: symbol = Symbol()

Flow 数组类型

/**
 * 数组类型
 *
 * @flow
 */

const arr1: Array<number> = [1, 2, 3]

const arr2: number[] = [1, 2, 3]

// 元组
const foo: [string, number] = ['foo', 100]

Flow 对象类型

/**
 * 对象类型
 *
 * @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 特殊类型

字面量声明,除了你声明的类型外,都不能赋值。

/**
 * 特殊类型
 *
 * @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
// 相当于
// const gender: number | null | void = undefined

Flow Mixed 与 Any

/**
 * Mixed Any
 *
 * @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)

Flow 运行环境 API

/**
 * 运行环境 API
 *
 * @flow
 */

const element: HTMLElement | null = document.getElementById('app')

在这里插入图片描述

TypeScript 概述

基于JS的扩展语言,最低能编译到ES3版本的代码。
任何一种JavaScript运行环境都支持TypeScript进行开发
相比于Flow,功能更为强大,生态更健全、更完善
很多大项目都使用TypeScript进行开发 – Angular/Vue3.0
TyperScript — 前端领域中都第二语言
缺点:
语言本身多了很多概念,提高了学习成本
项目初期,TypeScript会增加一些成本
![在这里插入图片描述](https://img-blog.csdnimg.cn/2020112122124877.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NTM0NTEwNQ==,size_16,color_FFFFFF,t_70#pic_cente

TypeScript 快速上手

安装: yarn add typescript --dev
编译: yarn tsc .\code\01-getting-started.ts
检查类型异常
如果没有报错,移除类型注解等扩展语法
自动转换ES新特性
生成配置文件: yarn tsc --init
直接运行yarn tsc编译整个项目,配置文件才会生效

TypeScript 配置文件

在这里插入图片描述

TypeScript 原始类型

// 原始数据类型

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

TypeScript 标准库声明

不指定库调用其他ES版本的方法或对象会报错。

在这里插入图片描述

TypeScript 中文错误消息

设置中文错误消息
在这里插入图片描述

TypeScript 作用域问题

// 作用域问题

// 默认文件中的成员会作为全局成员
// 多个文件中有相同成员就会出现冲突
// const a = 123

// 解决办法1: IIFE 提供独立作用域
// (function () {
//   const a = 123
// })()

// 解决办法2: 在当前文件使用 export,也就是把当前文件变成一个模块
// 模块有单独的作用域
const a = 123

export {}

TypeScript Object 类型

// Object 类型

export {} // 确保跟其它示例没有成员冲突

// object 类型是指除了原始类型以外的其它类型
const foo: object = function () {} // [] // {}

// 如果需要明确限制对象类型,则应该使用这种类型对象字面量的语法,或者是「接口」
const obj: { foo: number, bar: string } = { foo: 123, bar: 'string' }

// 接口的概念后续介绍

TypeScript 数组类型

// 数组类型

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

TypeScript 元组类型

// 元组(Tuple)

export {} // 确保跟其它示例没有成员冲突

const tuple: [number, string] = [18, 'zce']

// const age = tuple[0]
// const name = tuple[1]

const [age, name] = tuple

// ---------------------

const entries: [string, number][] = Object.entries({
  foo: 123,
  bar: 456
})

const [key, value] = entries[0]
// key => foo, value => 123

TypeScript 枚举类型

// 枚举(Enum)

export {} // 确保跟其它示例没有成员冲突

// 用对象模拟枚举
// const PostStatus = {
//   Draft: 0,
//   Unpublished: 1,
//   Published: 2
// }

// 标准的数字枚举
// enum PostStatus {
//   Draft = 0,
//   Unpublished = 1,
//   Published = 2
// }

// 数字枚举,枚举值自动基于前一个值自增  不指定就从0开始累积
// 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

双向键值对对象,可以通过key获取value,也可以通过value获取key
enum编译后的样子
在这里插入图片描述
编译成js后 enum会被移除,变成对应数值。
在这里插入图片描述

TypeScript 函数类型

// 函数类型

export {} // 确保跟其它示例没有成员冲突

function func1 (a: number, b: number = 10, ...rest: number[]): string {
  return 'func1'
}

func1(100, 200)

func1(100)

func1(100, 200, 300)

// -----------------------------------------

const func2: (a: number, b: number) => string = function (a: number, b: number): string {
  return 'func2'
}

TypeScript 任意类型

// 任意类型(弱类型)

export {} // 确保跟其它示例没有成员冲突

function stringify (value: any) {
  return JSON.stringify(value)
}

stringify('string')

stringify(100)

stringify(true)

let foo: any = 'string'

foo = 100

foo.bar()

// any 类型是不安全的

TypeScript 隐式类型推断

// 隐式类型推断

export {} // 确保跟其它示例没有成员冲突

let age = 18 // number

// age = 'string'

let foo

foo = 100

foo = 'string'

// 建议为每个变量添加明确的类型标注

TypeScript 类型断言

// 类型断言

export {} // 确保跟其它示例没有成员冲突

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

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

// const square = res * res

const num1 = res as number

const num2 = <number>res // JSX 下不能使用

TypeScript 接口

接口,一种规范,一种契约。

// 接口

export {} // 确保跟其它示例没有成员冲突

interface Post {
  title: string
  content: string
}

function printPost (post: Post) {
  console.log(post.title)
  console.log(post.content)
}

printPost({
  title: 'Hello TypeScript',
  content: 'A javascript superset'
})

TypeScript 接口补充

// 可选成员、只读成员、动态成员

export {} // 确保跟其它示例没有成员冲突

// -------------------------------------------

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
}

const cache: Cache = {}

cache.foo = 'value1'
cache.bar = 'value2'

TypeScript 类的基本使用

描述具体事务的抽象特征,例如手机是一类,子类必须有父类的共同特点,子类也可以有自己的特点。

// 类(Class)

export {} // 确保跟其它示例没有成员冲突

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}`)
  }
}

TypeScript 类的访问修饰符

// 类的访问修饰符

export {} // 确保跟其它示例没有成员冲突

class Person {
  public name: string // = 'init name'  ts中默认就是public
  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) 只有class内部可以访问
// console.log(tom.gender) 只有class内部可以访问   

const jack = Student.create('jack', 18)

protected和private区别,子类可以访问protected
在这里插入图片描述
如果 private修饰了construct就无法new,只能在内部new
在这里插入图片描述

TypeScript 类的只读属性

只能构造函数中初始化,或类型声明的时候初始化。

// 类的只读属性

export {} // 确保跟其它示例没有成员冲突

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

TypeScript 类与接口

一个接口对应一个能力会更合理一些,例如车也会跑,但不会吃。

// 类与接口

export {} // 确保跟其它示例没有成员冲突

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了,
抽象方法需要重写。

// 抽线类

export {} // 确保跟其它示例没有成员冲突

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)

TypeScript 泛型

作用:极大复用代码。调用的时候才声明。

// 泛型

export {} // 确保跟其它示例没有成员冲突

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')

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 typed')


export {} // 确保跟其它示例没有成员冲突

可安装loadsh对应声明模块可解决。在这里插入图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值