这是一份林一一同学学习 typescript4.0 的笔记,心愿能对前端er有帮忙。

介绍Typescript

Typescript 是什么?

图片起源网络,侵权删除

  • Typescript 是 JavaScript 的超集,两者是所属关系。
  • Typescript 是 JavaScript 的加强,蕴含 JavaScript 的最新个性,非常适合创立大型项目
  • Typescript 是动态语言与动静语言 JavaScript 不同,TS 是和 JS 都是弱类型语言
  • Typescript 也是前端的趋势,各大驰名的前端框架都应用了 TS 重构,如 Vue, React 等

下载安装及应用

  • 本地环境须要先下载 node vscode,随后关上 vscode 终端,应用 npm install -g typescript 即可
  • tsc -v 查看版本号,这份教程是最新的 typescript 4.0
  • 倡议装置 TSlint 插件标准代码
  • 编写 TS 文件代码,应用 tsc xx.ts 命令运行 ts 文件,运行 ts 文件后会生成相应的 js 文件,这个 js 文件时 tsc 将 xx.ts 代码编译成 xx.js的代码

动静语言和动态语言的差异

  • 动态语言在编写代码的时候就能发现潜在的谬误.
  • 动态语言更容易读懂代码,像下面的data参数动态语言能间接读出外面的属性 x, y,然而动静语言参数 data 显然不能间接读出外面蕴含什么属性。
// TSfunction tsFunc (data: {x: number, y: number}) {    console.log('demo ts')    return Math.sqrt(data.x ** 2 + data.y ** 2)}// tsFunc()  // 没有传入参数,这里的代码 vscode 会提醒谬误,这就是动态语言在编写代码的时候就能够晓得有谬误。tsFunc({x: 3, y: 4})  //须要将参数代码一起写入。// 再比方传入参数的个数,ts 能间接检测,然而生成的 js 文件不能检测function get(param) {    return param}get('hello')get('hello', 1)    // error: 应有 1 个参数,但取得 2 个
  • 编写代码时动态语言能辨认到可能应用到的属性等,但动静语言不肯定能提醒的正确。
// 动态类型和动静类型的差异,动态类型在编写代码时就能够发现错误像C++,Java等,动静类型的语言则须要代码运行时才能够晓得谬误,像JavaScript,python。// js-codefunction jsFunc (data) {    return Math.sqrt(x ** 2 + y ** 2)}jsFunc()  // 没有传入参数,但这里的代码 vscode不会提醒谬误,但理论运行会产生报错。

二. 动态类型

动态类型

就像后面看到的那样动态类型能够是根底类型 number string null undefined symbol boolean void enum 还能够是对象类型 Object,Array, class, function,还能够是自定义类型 interface 或任何类型 any 等详情 typescript官网

  • 定义为相应类型后能够间接应用对应类型的办法或属性如 number,vscode 间接提醒

. 根底类型 number string null undefined symbol boolean any void never。。。

  • number 类型
const num: number = 123
  • string 类型
const Name: string = 'LinYY'
  • boolean 类型
const boolean: Boolean = true
  • null 类型 。null 类型不能够赋值给 undefined 类型和 联结类型(前面介绍)
let n: null = null
  • undefined 类型
let u: undefined = undefined

undefined 类型。能够作用到可选类型,因为可选的类型默认会有一个undefined 类型

interface E {    b: number    c?: number}let e: E = {b: 12, c: 12}e = {b: 23, c: undefined}
  • any 类型。曾经定义变量的类型不能再批改,否则报错。
留神 any 类型,any 类型定义后能够批改为其余的类型
// any 类型能够批改成其余任何类型,TS 不对 any 类型作类型检测let not: anynot = 2not = '2'not = true// 解决不确定的数组类型 any 比拟适合。let listArr: any[] = ['1', 2, true]
  • void 类型 和 any 类型相同,示意没有任何类型
void 类型 通常作用在函数中代表没有返回值,尽管也能够作为其余变量的类型,但只能赋值成 undefined。换一个方向想函数总是有返回值的,如果不是一个确定的值那么就是 undefined 值,所以 void 其实是属于 undefined 的,所以一个变量类型是 void 时,值只能 undefined 值。然而 不能将类型“void”调配给类型“undefined”详情看例子
// void 空类型,个别用于函数,function noReturn(): void {    console.log('no value return')}function fn(): void {    // Error    return 3;  }function fn5(): void {}let un: undefined = fn5(); // Error 不能将类型“void”调配给类型“undefined”let voidValue: void = undefinedlet voidValue2: void = null   // 不能将类型“null”调配给类型“void”
  • never 一个非凡类型。简略的说如果函数是一个永远不会执行完的函数,返回值就是 never 类型,像函数 errorFuncabs
// never 类型,不会执行完结的函数类型function errorFunc(): never {    throw new Error()    console.log('never')    // 抛出谬误后 这段代码不打印。}function abs(): never {    while (true) {    }    console.log('never')    // 下面的代码永远是true 这段代码不打印。}
  • 对象类型 object type。object {},array [], class {}, function
let person: {    name: string,    age: number} = {    name: 'LinYY',    age: 12}// 或 (不举荐写法)let personB:{name: string} & {age: number} = {    name: 'LinYY',    age: 12}
  • 数组类型 也是对象类型,上面申明number型数组只能写入数字来初始化,写入字符串将会报错。
const list: number[] = [12, 23, 34]//等同于,上面的数组泛型,泛型是什么之后会讲,先留一个印象。const listA: Array<number> = [1, 2, 3]// const listB: number[] = ['12', 23, 34]
  • class类 类型
class Person {}const LinYY: Person  = new Person()
  • function 函数类型, 上面的函数类型要求返回值是 number 数字类型,写成其余类型如 string 会报错。
const getNumber: () => number = () => {    // return 'LinYY'   报错    return 123}// 要求返回值是string 字符类型const getString: () => string = () => {    return 'LinYY'    // return 123}
  • interface 自定义类型,也就是接口
interface Point {    x: number,    y: number}const point: Point = {    x: 2,    y: 4}
  • 多类型。变量的类型能够有多个,比方能够是 number 或 string类型
// 变量的类型能够有多个,比方能够是number或string类型。let temp: number | string = 23temp = '23'
  • type alias 类型别名,类型别名不是 TS 的根本数据类型,类型别名罕用于提取公共类型,上面 interface 接口会具体介绍
type User = { name: string, age: number }let male: User = {name: 'LinYY', age: 18}let famale: User = {name: 'nana', age: 18}

小 tip

正文小技巧tip: 应用 /** */ 能够给类型增加更敌对的提醒
// 正文/** * this is good Per */interface Per {    name: string}const p: Per ={    name: 'LinYY'}


在 typescript 外面 name 是一个预留关键字,不能间接当变量来用

三.类型注解和类型推断

type annotation 类型注解。

  • 间接申明的类型,通知TS变量是什么类型。比方这里的 count 是 number 类型
// type annotation 类型注解。let count: numbercount = 23

type inference 类型推断。

  • 没有间接申明类型,TS 会尝试去剖析变量类型,如这里的 countB,推断是 number 类型。(此处加图阐明)

let countB = 23
  • 然而申明的变量没有间接在一行赋值 TS 将默认变量为 any 类型,如这里的变量 countC,鼠标箭头挪动到 countC 上方就能够看到类型。正确写法是加上类型注解。
let countC    // any 类型countC = 233

TS 并不能所有的类型都能推断进去,那么什么时候应用类型注解呢?具体情况须要具体分析

  • 个别简略的变量申明能够不写类型注解。如这里的 num1 num2 sum。TS 能直接判断。
  • 个别函数的参数须要类型注解,返回值能够不必写类型注解,TS 能主动判断
  • 曾经有未确定的 any 类型,须要加类型注解,如 total 显示为 any,起因是类型 a b 不确定。
let num1 = 1let num2 = 2let sum = num1 + num2    // TS 推断出 sum 是 number 类型let obj = {    name: 'LinYY',    age: 18}// obj.name = 23 // TS 推断进去的类型 同样不能再批改// 须要类型注解function getSum(a, b) {    return a + b}const total = getSum(2, 3)

四.TS 函数

TS 定义函数的办法和 JS 根本一样,不同的是 TS 能够要求有无返回值。

  • TS 返回值的类型能够是 number string 等类型 也能够是 void 类型即没有返回值,也能够是联结类型。
// 要求返回值是 number 数字类型,上面两种写法等价。const fooFunc = (a: number, b: number): number => {    return a + b}//: (a: number, b: number) => number' 这里的具体意义是函数参数 a, b 类型是 number 型,返回值是 number 型,前面的 = 是跟函数的具体实现const foo1: (a: number, b: number) => number = (a, b) => {    return a + b}// 返回值是 void 空类型function sum2(a: number, b: number): void {    console.log(a + b)}// 联结类型function sum2(a: number, b: string): number | string {    return a || b}

TS 函数的类型解构正确用法

  • 退出类型注解能防止意外的bug,具体看实例
// 防止意外的 bug,当传入的 person 中没有 name 属性时上面的代码会报错,TS 能躲避这个问题给出报错提醒const getNameA = (person: {}) => {    console.log(person.name)  // ==> undefined}const getName1 = (person: { name: string }) => {    console.log(person.name)}
  • 解构一个函数的参数是 对象 的形式是在前面跟着一个对象类型注解,像函数 add()
  • 个别函数的参数须要类型注解,返回值能够不必写类型注解,TS 能主动判断
// 不退出对象类型的注解{a: number, b: number},返回值则不能保障是预期的类型.function add({ a, b }: { a: number, b: number }): number {    const c = a + b    return c}const sum1 = add({ a: 1, b: 2 })// 参数为对象的正确注解形式function getNumberA({ a }: { a: number }) {    return a}const totalA = getNumberA({ a: 1 })// 如这里不能保障放回值是number类型,因为a, b类型为any类型。function add2({ a, b }): number {    const c = a + b    return c}

TS 中的 this,TS 是 JS 的超集,this 的指向法令都一样

  • 了解 this 指向 对咱们应用 JS TS 特地重要,记住最要害的一点:this 永远指向最初调用它的那个对象
  • 解决 es5 的 this 应用的坑能够应用 箭头函数箭头函数在创立时就保留了最近上下文的 this 的值
this 指向最初调用 this 的对象

this 指向 示例一

let name = 'foo'let f = {    name: "Lin",    a: function () {        console.log(this.name) // ==> Lin    }}f.a() // f.a() == window.f.a()// 为什么是 Lin?因为 对象 f 调用了函数 a(),再调用了 this。下面 window 调用了 f 对象,然而 f 才是最初调用 this 的对象

再看示例二

var age = 18function foo() {    let age = 20    console.log(this.age) // ==>18}foo() // == window.foo()//为什么是18,不是20呢?下面 foo() 函数是 window 对象调用了,所以 this 指向 window,那么 应用的 age 也就是window下的 age

再看示例三

let name = 'LinYY'let a = {    name: 'lin',    c: function () {        return function () {            console.log(this.name)        }    }}let b = a.c()b()     // window.b()// 为什么这里 打印的是 LinYY 呢?和示例二相似,b() 最初是被 window 对象调用了,所以还是 “this 指向最初调用 this 的对象”

箭头函数解决 this指向

// 问:如果就是想要应用对象 a 上下文呢?那么就能够应用 箭头函数。保留最近的上下文的this,也就是这里的对象 alet name = 'LinYY'let a = {    name: 'lin',    c: function () {        return () =>  {            console.log(this.name)        }    }}let b = a.c()b()

五.数组和元组

数组的类型注解

数组的类型申明分为两种,一: 类型[], 二: Array<类型>,两种写法等价具体看上面示例
  • 同变量的类型注解,数组也能够具备多个类型,number,string等。
// 单类型注解数组 [ ],number[] 示意是数字类型的数组,其余同理const numberArr: number[] = [1, 2, 3]    // 等同于 const numberArr: Array<number> = [1, 2, 3]const stringArr: string[] = ['1', '2', '3']     // // 等同于 const stringArr: Array<string> = ['1', '2', '3']const undefinedArr: undefined[] = [undefined]// 多类型注解数组 [ ]const arr: (number | string)[] = [1, 2, '2']// 对象数组const objectArr: { name: string, age: 18 }[] = [{    name: 'LinYY',    age: 18}]
  • 对于简单的对象数组,能够采纳类型别名 type alias。
// 采纳类型别名 type aliastype User = { name: string, age: number }const objectArr1: User[] = [{    name: 'LinYY',    age: 18}]
  • 传入的数据结构和定义的 type alias 或 class 统一,也是能够的。
// 数据结构统一 TS 不会报错class Teacher {    name: string = ''    age: number = 0}// 这里是一个 Teacher 类,那么每一个元素都应该是 Teacher 的实例,然而因为上面的对象数据结构和 Teacher类统一,所以 TS 没有报错。const objectArr2: Teacher[] = [    new Teacher(),    {        name: 'LinYY',        age: 18    }]// 反例:因为 Teacher 类中没有 other 属性,TS 会提醒 “other”不在类型“Teacher”中 const objectArr3: Teacher[] = [     new Teacher(),     {     name: 'LinYY',     age: 18,     other: 0 }]

元组 tuple 是一种非凡的数组 (TS 新增)

  • 简略的说元组是每个元素都有固定的类型且无限数目的数组。
  • 元组解决了一般数组不能规定每一项元素类型的问题。
  • 元组的元素同样有对象的类型操作方法
  • 在 3.1 及之前版本中,超出规定个数的元素称作越界元素,然而只有越界元素的类型是定义的类型中的一种即可。比方咱们定义的类型有两种:string 和 number,越界的元素是 string 或 number 类型,属于联结类型,然而在 3.1 之后的版本,去掉了这个越界元素是联结类型的子类型即可的条件,要求元组赋值必须类型和个数都对应。越界元素间接时 undefined类型
// tuple 元组的定义let arrT: [number, string, number]arrT = [18, 'LinYY', 3]// 元素操作方法arrT[0].toExponential(1)arrT[1].split('i')arrT[2] = 4// 类型不对应就会报错arrT = [18, 'LinYY', '1']// 越界元素,间接报错arrT[3] = '12' // 不能将类型“"12"”调配给类型“undefined”type tupleArr =  [number, string, number]const arrTB: tupleArr = [18, 'LinYY', 3]const attTC: tupleArr[] =[    [18, 'LinYY', 3],    [1, 'LinYY', 23],    [2, 'LinYY', 13]]// 一般数组不能束缚每一项元素的类型,上面元素的类型就不能够束缚let list: (number | string)[] = ['LinYY', 18] let listB: (number | string)[] = [18, 'LinYY']
  • 应用场景:批量的来获取参数,并且每一个参数的类型还不一样
/**巧用元组 */function getParams(...arry:[string, number, boolean]){    const str: string = arry[0];    const num: number = arry[1];    const b: boolean = arry[2];}

六.interface 接口

  • 简略点了解 interface 接口其实是一个类对象,类对象外面有属性或办法,同样通过 '.' 元字符操控属性和办法,属性和办法又有相应的类型 string,number
  • 能定义对象类型和函数类型,个别应用在类型中,接口类型个别大写首字母
// 一个简略实例示例阐明 interface 是一个类对象interface PersonA {    firstName: string,    lastName: string}function greeter(person: PersonA) {    return person.firstName + person.lastName}let userA = {    firstName: 'lin',    lastName: 'YY'}greeter(userA)
  • 还能定义当前可能用到的属性,在属性前面加上'?',相似函数可选参数,如示例
// 可能用到的属性,在属性前面加上'?',interface Person {    name: string,    age: number,    age1?: number,   // age1 是接口可能用到的属性。    readonly ID: number}const person: Person = {    name: 'LinYY',    age: 18,    // age1: 0,    ID: 101}
  • 只读属性 能对属性定义进行只读操作 readonly,在对应属性背后加上 readonly 就能限定只读操作。只读属性被初始化后的值不能在被批改。
// 只读操作 readonly 不传入 age1 也能够通过校验const getName = (person: Person) => {    // Person 是下面的 interface 接口    console.log(person.age)    // console.log(person.age1)  ==> 0    console.log(person.ID)    // person.ID = 200     // 报错 ID只能读取,不能批改==> error TS2540: Cannot assign to 'ID' because it is a read-only property}getName(person)
  • interface 中还能定义方法,跟着的类型示意返回值类型。
// interface 中定义方法interface Search{    (a: number, b: number): boolean}let search: Searchsearch = function(a: number, b: number): boolean {    return a >= b}search(2, 3)// 或interface Action {    name: string,    age: number,    say(): string}const applySay = (action: Action) => {    console.log(action.say())}const action = {    name: 'LinYY',    age: 18,    say() {        return 'hello TS'    }}applySay(action)// 上面定义了一个 say 类型的接口 承受一个 string 的参数,返回 string 类型的字符串interface Say {    (word: string): string}const foo: Say = (word: string) => {    return word}foo('hello TS')   //  ==> 'hello TS'
  • interface 间还能互相嵌套
/**interface 间还能互相嵌套 */interface A {    name: string,    age: number}interface B {/** person is interface a */    person: A}
  • 也能够被类 class 通过 implements 应用,实现(implements)是面向对象中的一个重要概念,简略点了解就是实现接口 interface 中属性和办法,详情参考官网 implements
// implements 和 extend 不同 extend 是继承父类,implement 是实现接口 interface 而且能够应用多个接口,用逗号隔开。// class A extends B implements C,D,Einterface Person {    name: string,    age: number,    age1?: number,   // age1 是接口可能用到的属性。    readonly ID: number}class test implements Person {    name = 'LinYY'    age = 18    ID = 301}
  • interface 还能够被其余接口继承 extends
// 被其余接口继承 extendsinterface Music {    click: boolean}interface Sentence {    color: string}interface Classic extends Music, Sentence {    time: number}let classic = {} as Classicclassic.click = falseclassic.color = 'white'classic.time = 220// 或interface PersonB {    name: string,    age: number,    age1?: number,   // age1 是接口可能用到的属性。    readonly ID: number}interface Teach extends PersonB {    action(): string}const teach: Teach = {    name: 'LinYY',    age: 28,    ID: 501,    action() {        return '222'    }}// 或应用 '<类型>' 示意类型const teachA = <Teach>{    name: 'LinYY',    age: 28,    ID: 501,    action() {        return '222'    }}
  • interface 能够继承类吗?能够!
// interface 继承 class 示例class Animal {     fly: any}interface Dog extends Animal {    run(): void}

留神点

  • interface 接口中不强制规定起初加上的属性,只有传入参数满足 interface 接口已有的属性,也能通过 如示例二,age,sex 属性不在接口 Person 中也能通过校验
// 示例二function printName(obj: { name: string }) {    console.log(obj.name)}let myObj = { name: 'LinYY', age: 18 }printName(myObj)// 或const getAge = (person1: Person) => {    console.log(person1.age)}const per = {    name: 'LinYY',    age: 18,    ID: 201,    sex: 'male'     // 不在 Person 接口内,也能够通过校验}getAge(per)
  • 然而以字面量模式传入不在接口中的属性,TS 会强校验导致报错。
// 以字面量的模式传入,TS 会强校验导致校验不通过。 getAge({     name: 'LinYY',     age: 18,     ID: 201,     sex: 'male'     // ==>  'sex' does not exist in type 'Person' })
interface 实际上在编译成 JS 后并没有相应的代码,其实 interface 就是 TS 来束缚代码代码标准的。

怎么无效解决当前开发的过程中可能会退出的属性呢?

  • 能够间接在 interface 接口中退出当前可能会用到的属性如,string 类型 [propName: string]: any,如示例三
// 示例三 [propName: string]: anyinterface User {    name: string,    age: number,    [propName: string]: any // 前期可能用到的 string 类型的属性}const getSex = (user: User) => {    console.log(user.age)}const user = {    name: 'LinYY',    age: 18,    ID: 201,    sex: 'male'     // 不在 User 接口内,但也能通过}getSex(user)// 以字面量的模式传入也能够。getSex({    name: 'LinYY',    age: 18,    ID: 201,    sex: 'male'})

interface 和 type alias 关系

两者用法下面没有太大的区别,同样都能够扩大,只是语法不同,type 应用穿插类型 &。而且两者相互之间能够继承。然而 interface的利用场景更加的广,可能应用interface就不必type
// interface 和 type alias/** ifc is interface */interface Ifc {    name: string,    age: number}/** T is type alias */type T = {    name: string,    age: number}/* interface 和 type alias 扩大示例 */interface IfcName {    name: string}interface IfcAge extends IfcName {    age: number}type TName = {    name: string}/** TAge 继承了 TName 的 name 属性*/type TAge = TName & {    age: number}const tAge : TAge = {    name: 'LinYY',    age: 18}/* interface 和 type alias 互相继承示例 *//** interface  extends type alias */interface IfcAge extends TName {    age: number}/** type & interface alias */type TypeName = IfcAge & {    name: string}

更多细节 官网 / 或

七.class 类

TS 中类的继承和定义和 JS 基本一致

  • 同样也能重写父类的属性
  • 子类中有结构器 就必须要调用 super()。
// TS 中类的定义class PersonA {    name: string    constructor(msg) {        this.name = msg    }    getName() {        return this.name    }}const personA = new PersonA('LinYY')console.log(personA.getName())   // ==> LinYY// TS 类的继承class Student extends Person {    say() {        return this.name    }    getName() {        return 'LinYY'  // 重写父类 getName办法    }}const student = new Student()console.log(student.say())   // ==> LinYY

TS 类中的拜访类型,结构器和 JS 也基本一致

拜访类型 private,public,protected

  • 当类的属性不写访问类型时,默认是 public。public 在类的内外都能够拜访。
  • private,protected都只能在类内应用,另外 protected 能够在继承的子类中应用。

constructor 结构器,在类实例初始化时执行

  • TS 中使用 constructor 示例如下。
  • 子类继承父类,子类中应用 constructor,就须要调用 super()函数。
// constructor 示例class PersonB {    public name: string    constructor( name: string) {        this.name = name    }}// 简化写法,举荐。// class PersonB {//     constructor(public name: string) {//     }// }const personB = new PersonB('LinYY')class TeacherA extends PersonB {    constructor(public age: number ) {        super('LinYY')  // 初始化父类的 name    }}const teacher = new TeacherA(18)
  • class 的基本概念和用法能够拜访 阮老师的 ES6入门教程
  • TS 动态属性 static 和 JS 一样。在类的内外都是通过类名来间接拜访,且不能被继承,在静态方法中应用另一个静态方法能够间接调用 this。非静态方法不行**
// static class GetAge {    static  age = 18    static printAge() {        console.log(GetAge.age)    }    static setAge(msg: number) {        this.age = msg        this.printAge()    }}
  • 和 interface 一样 class 也能够当作接口应用
// 将 class 当作接口应用class A {    x: number    y: number    constructor(x: number, y: number) {        this.x = x        this.y = y    }}interface B extends A {    z: number}let printA: A = {x: 2, y: 3}

TS 类中的动态属性,取值函数(getter)和存值函数(setter),对某个属性设置存值函数和取值函数,拦挡该属性的存取行为。

Getter 的应用

  • 定义 get 的属性外表上是一个函数,在调用时不须要加上 '()',这是 get 的写法。
  • 拜访类中的公有属性能够通过 get 属性,写入一个‘办法’返回公有属性

Setter 的应用

  • 设置公有属性能够通过 set 属性,同样也是写入一个‘办法’,简略的说也就是赋值
class Person {    constructor(private _name: string){}    // 公有属性个别加下划线 '_'    get name() {        return this._name    }    set name(rename: string) {        this._name = rename    }}// getconst person = new Person('LinYY')console.log(person.name)    // ==> LinYY 调用 get 上面的 name 属性// setperson.name = 'LinYYB'  // 调用 set 上面的 name 属性同时赋值console.log(person.name)    // ==> LinYYB

润饰器 readonly 也能够设置类的只读属性

// 装璜器`readonly`用来装璜“类”的`name`属性。class PersonB {    readonly name: string    constructor(private _name: string){        this.name = _name    }    // 公有属性个别加下划线 '_'}

抽象类 abstract 目标是将有很多共性的办法或属性抽离进去

  • 抽象类个别拿来做公共的类
  • 抽象类外面能够写入形象办法,形象办法不能具体的实现,如 getApiData()
  • 抽象类只能被继承不能被实例化
  • 子类继承抽象类后,抽象类的形象办法必须在子类外面实现,否则报错。
  • 抽象类和 interface 有类似,interface 同样也能够抽离一些专用办法和被继承。
import axios from 'axios'// 抽象类 abstractabstract class Classic {    name: string   async submit() {        return 'LinYY'    }    abstract getApiData()   // 一个形象办法}// const classic = new Classic()   //  error: 无奈创立抽象类的实例,只能被继承class Music extends Classic {    async getApiData() {      return await axios.get('api1URL').then( res => {          console.log(res)      }).catch( e => {        console.log(e)    })    }}class Book extends Classic {    async getApiData() {      return await axios.get('api2URL').then( res => {          console.log(res)      }).catch( e => {          console.log(e)      })    }}class Sentence extends Classic {   async getApiData() {      return await axios.get('api3URL').then( res => {          console.log(res)      }).catch( e => {        console.log(e)    })    }}

八.TS 穿插类型和联结类型和类型爱护

穿插类型

  • 穿插类型通过'&' 将两个或多个类型合并到一起
  • 穿插类型能够获取合并类型的所有属性
// 穿插类型interface Colors {    red: string}interface Rectangle {    height: number    width: number    area: () => number}// param 参数能够拜访类型 Colors 和 Rectangle 所有属性function getArea(param: Colors & Rectangle) {    param.height = 2    param.width = 3    param.red = 'red'    param.area = (): number => {        return param.height * param.width    }}

联结类型

  • 通过 '|' 运算符将两个类型组合在一起
  • 联结类型能够间接提醒出共有属性,但不能提醒出公有属性
//  联结类型let bar: string | number = 12bar = '12'interface Bird {    fly: Boolean;    sing: () => {}}interface Dog {    fly: Boolean;    dark: () => {}}// animal 参数能够是 Bird 或 Dog,语法提醒能够间接提醒出共有属性 fly,然而不能间接提醒出 sing 和 dark。function trainAnimal(animal: Bird | Dog) {    animal.fly    // animal.dark() 这里间接报错,因为不能确保 animal 蕴含 dark 办法。}

类型爱护

  • 类型断言:让编辑器采纳开发者的类型申明
  • 类型断言,通过 as,通知 TS 以后的类型
//类型爱护——类型断言 asfunction trainAnimal1(animal: Bird | Dog) {    if (animal.fly) {        (animal as Bird).sing() //间接通知 TS 这里 animal 是 Bird 类型        // 或上面的一种写法        // (<Bird>animal).sing()    } else {        (animal as Dog).dark()    }}
  • 通过 in 判断含有的公有属性
// in 判断function trainAnimal2(animal: Bird | Dog) {    if ("sing" in animal) {   // 判断 animal中是否含有公有属性 sing        animal.sing()    } else {        animal.dark()    }}
  • typeof,instanceof 类型于下面两种都能够作类型爱护
// typeof 类型爱护function trainAnimal3(paramA: number | string, paramB: number | String) {    if (typeof paramA === "string" && typeof paramB === "string") {        return paramA + paramB    }    return}
  • null 的类型爱护 能够通过 '!' 操作符
// null 类型爱护function fn(params: string | null) {    // params.length   // 对象可能为 "null"    return params!.length   // 将参数的可能类型 null 类型排除}fn('12121')fn(null)

九.Enum 枚举类型

  • 概念:枚举是什么? 枚举是一种数据类型,是对 JavaScript 类型的补充,其实也是一个对象
  • 用处:个别是对类似的类型赋予一个敌对的名字,如色彩有很多种通称为 Color 等
  • 应用:同样相似于 interface 接口,enum 也是通过元字符 '.' 操控属性
  • 每一个枚举类型都有一个下标,默认从 0 开始,下标值能够用等号赋值批改
  • 从哪里扭转枚举下标值,则按那里开始下标加一,如 ONLINE = 3,则OTHERS将会打印出4,OFFLINE 不变还是0
  • 援用 enum 的下标,同样也能够打印出下标对应的值。
// 枚举是一种数据类型enum Color {    Red,    Blue,    Black}let color: Color// 类型也只能是枚举 Color 类型color = Color.Redcolor = Color.Blueconsole.log('color', color) // ==> 打印出下标 1// 枚举个别首字母大写enum Status  {    // OFFLINE = 1,    OFFLINE,    ONLINE,    OTHERS}// 比照罕用的 JS 代码// const Status = {//     OFFLINE : 0,//     ONLINE: 1,//     OTHERS: 2// }function getStatus(status: Number) {    if(status === Status.ONLINE) {        return 'online'    }else if (status === Status.OFFLINE) {        return 'offline'    }else if(status === Status.OTHERS) {        return 'others'    }    return 'error'}const result = getStatus(Status.OFFLINE)console.log(result)// 上面代码间接打印出 enum 的下标值console.log(Status.OFFLINE)console.log(Status.ONLINE)console.log(Status.OTHERS)// 打印下标对应的属性console.log(Status[0])console.log(Status[1])console.log(Status[2])

原理:为什么枚举能够通过下标的形式索引 key 和 反索引 value呢?

  • 通过 tsc 编译后的 js 文件能够看到 enum 其实一个对象,如 Color[Color["Red"] = 0] = "Red" ; 通过 "Red"能够查看下标 0,通过下标 0 也能够查看 "Red"
// 通过 tsc 编译后的 js 文件var Color;(function (Color) {    Color[Color["Red"] = 0] = "Red";    Color[Color["Blue"] = 1] = "Blue";    Color[Color["Black"] = 2] = "Black";})(Color || (Color = {}));

十.TS 泛型

泛型概念:泛指的类型不具体针对某一特定的类型。

  • 应用'<类型>'示意泛型,类型能够是任意变量
//泛型简略示例function foo<T>(a, b, c) {    return a || b || c}// 或function foo<U>(a, b, c) {    return a || b || c}function id<T>(a: T, b: T, c: T): T {    return a || b || c}// 不针对某一特定类型,能够是 number,string,Boolean,interface等类型,且应用的类型必须统一。interface Type {    a: number    b: number    c: number}let t: Type = {a: 2, b: 3, c: 4}id(1,2,3)id('1', '2', '3')id(false, true, false)id(t.a, t.b, t.c)// 接口泛型 举荐写法,间接应用泛型参数 T 代表指定类型interface Uni<T> {    a: T    b: T    c: T}let uni: Uni<number> = {a: 2, b:3, c:4}id(uni.a, uni.b, uni.c)

函数泛型 Generics,泛指的类型和一般类型用法基本一致

  • TS 的泛型是 TS 比拟高级的用法,对于更多的 TS 泛型能够参考这篇 你不晓得的 TypeScript 泛型
  • 泛型起到的作用有点相似待指的两头类型,具体看例子
function add(a: number | string, b: number | string) {    return `${a}${b}`}// 如果要求输出的参数 a, b只能是同一个类型的参数该怎么实现?上面几种写法都不能实现add(1, 2)add('1', 1)add(1, '1')// 上面援用函数泛型实现,<T> 就是函数 add 要泛指的类型,前面的参数 a,b都要是这个类型。function add<T>(a: T, b: T){    return `${a}${b}`}//让输出的类型是 number 或 string,即<T>代表类型 Number或Stringadd<number>(1, 1)add<string>('1', '2')add<number>(1, '1') //提醒报错 "1"的类型不是 number 型add<string>('1', 2)  //提醒报错 2 的类型不是 string 型
  • 泛型同样能够继承 interface。
// 泛型同样能够继承 interface。interface LengthPro {    age: number | null    moreAge: number}function arg<T extends LengthPro>(params: T) {    return params.age || params.moreAge}arg({age: 18, moreAge: 20})arg({age: null, moreAge: 20})
  • 还能够对函数泛型进行束缚
//将函数的泛型指定为 ABC,参数的泛型是数组类型ABC,返回值也是数组类型ABC。function func<ABC>(a:ABC[]): ABC[]{    return a}// 或 function func1<ABC>(a:Array<ABC>): Array<ABC> {     return a }func<number>([123])// 谬误的输出func<number>(123)  // 类型“123”的参数不能赋给类型“Number[]”的参数
  • 泛型中能够写入多个泛型,对函数的参数有不同的类型束缚
// 多泛型束缚function moreT<T, Y>(a:T, b: Y) {    return `${a}${b}`}moreT<number, string>(1, '2')// K extends keyof T,让泛型 K 继承 T 的 keyof 的属性function getObjVal<T, K extends keyof T>(obj:T, key: K) {    return obj[key]}let o = {a: 1, b: 3, c: 4}getObjVal(o, 'a')getObjVal(o, 'd')   // 'd' 不是 对象 o 上面的 keyof 属性。

类的泛型

// 类泛型的一般写法class GenericType<T> {    numberVal: T    constructor(numberVal: T) {        this.numberVal = numberVal;      }     add(x: T, y: T) {    }}let numberType = new GenericType<number>(2)numberType.numberVal = 1numberType.add(2, 8)let stringType = new GenericType<string>('a')stringType.numberVal = 'b'stringType.add('a', 'b')// 或class GetItem<T>{    constructor(private data: T[]) { }    getName(index: number) {        return this.data[index]    }}const getItem = new GetItem(['LinYY'])const res = getItem.getName(0)console.log(res)
  • 泛型能够被继承,继承后必须全副含有继承对象的所有属性
// 继承示例 extendsinterface personA {    name: string,    age: number}class GetItemSecond<T extends personA>{    constructor(private data: T[]) { }    getName(index: number) {        return this.data[index].name    }}const getItemSecond = new GetItemSecond([    {        name: 'LinYY',        age: 18            // 这里不传入 age 时会飘红,必须传入所有属性    }])const res1 = getItem.getName(0)console.log(res1)
  • 也能够束缚泛型的类型范畴,number 或 string
// 束缚泛型的范畴function getData<T extends number | string>(param: T) {    return param}getData(1)getData('1')
  • 多泛型的束缚用逗号分隔,泛型之间也通过继承 extends 来互相束缚
// 多泛型束缚function moreT<T, Y>(a:T, b: Y) {    return `${a}${b}`}moreT<number, string>(1, '2')// K extends keyof T,让泛型 K 继承 T 的 keyof 的属性function getObjVal<T, K extends keyof T>(obj:T, key: K) {    return obj[key]}let o = {a: 1, b: 3, c: 4}getObjVal(o, 'a')getObjVal(o, 'd')   // 'd' 不是 对象 o 上面的 keyof 属性。
下面泛型的应用规定不局限在类或函数内

十一.TS 配置项

tsconfig.json文件文档

tsconfig.json是 TS 编译成 JS 代码的辅助文件

  • 调用 tsconfig.json 文件间接应用 tsc 命令即可,须要留神的是这样会编译所有 ts 文件
  • "compilerOptions"是各编译的选项,能够增加额定的配置项比方 "include"指定要编译的 TS 文件, "exclude"指定不要编译的 TS 文件,示例 "include": ["/demo.ts"]

罕用的 compilerOptions 编译配置项

  • "removeComments": true,编译过程中主动去掉正文
  • "noImplicitAny": true,要求编译的 TS 代码不能带有未指定的类型,即使是any 也须要显示的写明
  • "strictNullChecks": true, 强制进行 null 校验。
  • "rootDir" 和 "outDir", rootDir 是指定要 build 打包的文件,而 outDir 是 build 后的生成文件,两者前面都是跟指定的目录文件。
  • "allowJs": true,是将 js 文件也编译一遍,编译成 es5 的文件
  • "checkJs": true,能间接像 TS 一样检测 JS 的语法错误,不须要在运行后才提醒有错
  • "noUnusedLocals", "noUnusedParameters"用来检测定义了却没有被应用的变量或函数参数。

十二.TS 高级技巧(继续更新中)

很感激你能看到这里,心愿这份教程能对你有一点点帮忙 ????,我是林一一,下次见。

掘金地址

博客地址 体验成果更好。**

源码地址 欢送start (issue),当前会一直的更新内容**

参考:《Typescript官网》《Typescript实战技巧》《你不晓得的Typescript高级技巧》《Typescript高级技巧》《你不晓得的Typescript泛型》《Typescript深入浅出》。。。