Typescript

ts简介

ts是以js为基础的语言
是js的超集,
拓展了js,
添加了类型

ts不能被js解析器直接执行,需要把ts编译为js
可以编译为任意版本的js
便于维护

ts的安装与运行

  1. 安装ts

    npm install -g typescript
    
  2. 查看ts版本

    tsc -v
    
  3. 将ts文件转为js文件

    tsc 文件名.ts
    
  4. 执行js文件

    node 文件名.js
    

简化上述执行过程

  1. npm i -g ts-node
  2. npm init -y 生成 package.json文件
  3. 安装声明文件 npm i @types/node -D
  4. 直接执行ts文件 ts-node xxx.ts

数据类型

any、unknown
Object
Number、String、Boolean、
number、string、boolean、
1、'str'、true
never

number

let n: number = 1
console.log(n) //1

string

let s: string = 'hello,ts!'
console.log(s) //hello,ts!

boolean

let flag: boolean = true
if (flag) {
  console.log('hello') //hello
} else {
  console.log('ts')
}

null、undefined

  1. null

    表示对象值缺失,空对象引用

    console.log(typeof null) //object
    console.log(typeof undefined) //undefined
    
  2. undefined

    用于初始化变量为一个未定义的值

any、unknown

  1. any

    任意类型
    当该变量的类型不确定时,可以定义为any
    
    声明为any类型的变量
    可以被赋予任意类型的值
    也可以赋值给任意类型的变量
    
  2. unknown

    未知类型
    
    声明为unknown的变量
    可以被赋予任意类型的值
    只能赋值给unknown或any类型的变量
    
    unknown类型的变量读不到自身任何属性
    

void、never

  1. void

    用于标识方法返回值的类型, 表示该方法没有返回值
    
    function sayHi(): void {
      console.log('hi!')
    }
    sayHi()
    
  2. never

    • 代表从不会出现的值

      type t = number & string //type t = never
      
    • 在联合类型中会被排除掉

      type T = string | number | never //type T = string | number
      
    • never 类型的变量只能被 never 类型所赋值

      let x: never
      // never 类型可以赋值给 never类型
      x = (() => {
        throw new Error('exception')
      })()
      
    • 返回值为 never 的函数可以是抛出异常的情况

      // 返回值为 never 的函数可以是抛出异常的情况
      function error(message: string): never {
        throw new Error(message);
      }
      
    • 返回值为 never 的函数可以是无法被执行到的终止点的情况

      // 返回值为 never 的函数可以是无法被执行到的终止点的情况
      function loop(): never {
        while (true) {}
      }
      

数组

  1. 定义普通类型的数组

    const arr: number[] = [1, 2, 3]
    const arr2: Array<number> = [1, 2, 3]
    
    interface A {
      [index: number]: string
    }
    const arr: A = ['1', '2', '3']
    
  2. 定义对象类型的数组

    interface Obj {
      name: string
    }
    const arr3: Obj[] = [{ name: 'ym' }]
    
  3. 定义二维数组

    const arr: number[][] = [[1, 2, 3]]
    const arr2: Array<Array<number>> = [[1, 2, 3]]
    
  4. 定义函数中的剩余参数数组和伪数组

    function fn(...args: number[]) {
      const arr: IArguments = arguments
      console.log(args, arr)
    }
    fn(1, 2, 3)
    

元组 tuple

用来表示已知元素数量和类型的数组,各元素的类型不必相同,但对应位置的类型需要相同
即数量和类型有限的数组
let yuanzu: [number, string, boolean] = [1, '123', true]
console.log(yuanzu) //[ 1, '123', true ]

枚举 enum

  1. 默认情况下,从0开始为元素编号;当red=3时,表示从3开始为元素编号

    enum Color {
      // red,
      red = 3,
      pink,
      blue
    }
    let r: Color = Color.red
    let p: Color = Color.pink
    let b: Color = Color.blue
    // 当red没赋值时,打印结果为 0 1 2
    console.log(r, p, b)
    // 当red没赋值3时,打印结果为 3 4 5
    
  2. red 的值是被计算出来的。注意注释部分,如果某个属性的值是计算出来的,那么它后面一位的成员必须要初始化值。

    function getValue() {
      return 3
    }
    enum Color {
      red = getValue(),
      pink = 6,// 此处必须要初始化值,不然编译不通过
      blue
    }
    let r: Color = Color.red
    let p: Color = Color.pink
    let b: Color = Color.blue
    
    console.log(r, p, b) //3 6 7
    
    // 可以根据枚举的值可到名字
    console.log(Color[6]) //'pink'
    
  3. 反向映射

    // 上述例子中,可以根据枚举的值得到名字
    console.log(Color[6]) //'pink'
    
  4. 数字枚举

    enum Color {
      red,
      green,
      blue
    }
    console.log(Color.red) // 0
    console.log(Color.green) // 1
    console.log(Color.blue) // 2
    
  5. 增长枚举

    enum Color {
      red = 10,
      green,
      blue
    }
    console.log(Color.red) // 10
    console.log(Color.green) // 11
    console.log(Color.blue) // 12
    
  6. 字符串枚举

    enum Color {
      red = 'red',
      green = 'green',
      blue = 'blue'
    }
    
  7. 异构枚举

    enum Color {
      yes = 1,
      no = 'no'
    }
    
  8. 接口枚举

    enum Color {
      red = 'red',
      green = 'green',
      blue = 'blue'
    }
    interface Obj {
      color: Color.red
    }
    const obj: Obj = {
      color: Color.red
    }
    
  9. const枚举

    enum Color {
      red,
      green,
      blue
    }
    console.log(Color.red)
    
    // 会编译为
    
    var Color;
    (function (Color) {
        Color[Color["red"] = 0] = "red";
        Color[Color["green"] = 1] = "green";
        Color[Color["blue"] = 2] = "blue";
    })(Color || (Color = {}));
    
    console.log(Color.red);
    
    const enum Color {
      red,
      green,
      blue
    }
    console.log(Color.red)
    
    // 会编译为
    
    console.log(0 /* Color.red */);
    

接口 interface

用接口定义对象类型的数据

  • 接口重复定义会合并

  • 任意属性(索引签名)

    interface A {
      name: string
      [propName: string]: any
    }
    
  • 可选属性 ?

    interface A {
      age?: number
    }
    
  • 只读属性 readonly

    interface A {
      readonly id: string
      readonly fn: () => void
    }
    
  • 接口继承 extends

    interface A {
    }
    interface B extends A {
    }
    
  • 定义函数类型

    interface Fn {
      (name: string): number[]
    }
    const fn: Fn = function (name: string) {
      return [1]
    }
    const fn2: Fn = (name: string) => {
      return [1]
    }
    

函数类型

可选参数使用?标识

可选参数必须跟在必选参数后面

参数不能同时设为可选的和默认值

  • 定义参数类型和返回值类型

    function fn(a: number, b: number): number {
      return a + b
    }
    const fn2 = (a: number, b: number): number => {
      return a + b
    }
    
  • 函数默认参数

    function fn(a: number = 1, b: number = 2): number {
      return a + b
    }
    const fn2 = (a: number = 1, b: number = 2): number => {
      return a + b
    }
    
  • 函数可选参数

    function fn(a?: number, b?: number) {}
    const fn2 = (a?: number, b?: number) => {}
    
  • 函数参数为对象时

    interface User {}
    function fn(user: User): User {
      return user
    }
    
  • 定义函数this类型

    第一个参数指定this的类型

    interface User {
      arr: number[]
      add: (this: User, num: number) => void
    }
    let user: User = {
      arr: [1, 2, 3],
      add(this: User, num) {
        this.arr.push(num)
        console.log(this.arr)
      }
    }
    user.add(4)
    

内置对象

let a: Number = new Number(123)
let b: String = new String('123')
let c: Boolean = new Boolean(true)
let d: Date = new Date()
let e: Error = new Error('出错了')

// HTML(元素名称)Element、HTMLElement、Element
let div: HTMLDivElement | null = document.querySelector('div')
let span: HTMLSpanElement | null = document.querySelector('span')
let ipt: HTMLInputElement | null = document.querySelector('input')
let divs: NodeListOf<HTMLDivElement> = document.querySelectorAll('div')

let localS: Storage = localStorage
let sessionS: Storage = sessionStorage
let lo: Location = location
let p: Promise<string> = new Promise(resolve => {
  resolve('123')
})

类 class

  • 在类中定义变量

    不允许直接在constructor中使用变量,需要在constructor上面先声明

    class Test {
      name: string
      constructor(name:string) {
        this.name = name
      }
    }
    
  • 修饰符

    public 公共的,都可以访问
    private 私有的,只能在自身类中访问
    protected 受保护的,只能在自身类及其子类中访问
    static 静态属性和方法,只能通过类访问;静态的属性和方法中的this只能访问到静态属性和方法
    
  • class implements interface,interface

    interface IP1 {
      name: string
    }
    interface Ip2 {
      age: number
    }
    class Person implements IP1, Ip2 {
      age: number
      name: string
    }
    
  • 抽象类、抽象方法

    abstract class A {
      abstract study(): void
    }
    // 无法创建抽象类的实例
    // new A()
    class B extends A {
      // 非抽象类“B”不会实现继承自“A”类的抽象成员“study”
      study(): void {
        console.log('study')
      }
    }
    
  • 综合案例

    ::: details

    interface Options {
      el: string | HTMLElement
    }
    interface VueClass {
      options: Options
      init(): void
    }
    interface Vnode {
      tag: string
      text?: string
      children?: Vnode[]
    }
    class Dom {
      createElement(el: string) {
        return document.createElement(el)
      }
      setText(el: HTMLElement, text?: string | null) {
        el.textContent = text || null
      }
      render(data: Vnode) {
        let root = this.createElement(data.tag)
        if (data.text) {
          this.setText(root, data.text)
        }
    
        if (data.children) {
          data.children.forEach(item => {
            let child = this.render(item)
            root.appendChild(child)
          })
        }
        return root
      }
    }
    class Vue extends Dom implements VueClass {
      options: Options 
      constructor(options) {
        super() //调用父类的构造函数 父类的prototype.constructor.call
        this.options = options
        this.init()
      }
    
      init(): void {
        let data: Vnode = {
          tag: 'div',
          text: '我是div',
          children: [
            {
              tag: 'span',
              text: '我是div中的span'
            }
          ]
        }
        let app = typeof this.options.el === 'string' ? document.querySelector(this.options.el) : this.options.el
        app?.appendChild(this.render(data))
      }
    }
    
    const v = new Vue({
      el: '#app'
    })
    
    

    :::

extends

extends 关键字用于检查一个类型是否是另一个类型的子类型

  1. extends关键字在【条件类型】中的使用

    【分布式条件类型】:分布式条件类型是条件类型的一个特性,当条件类型遇到联合类型时,会被应用到联合类型的每一个成员上,这就是所谓的“分布式”行为。

    例如,有一个条件类型 T extends U ? X : Y,如果 T 是一个联合类型 A | B | C,那么这个条件类型就会被展开为

    (A extends U ? X : Y) | (B extends U ? X : Y) | (C extends U ? X : Y)
    

    例子:

    type A = number | string | boolean
    type B = boolean
    
    type CustomExclude<T, K> = T extends K ? never : T
    
    type C = CustomExclude<A, B> //type C = string | number
    
    type C = CustomExclude<A, B>
    // 解释:
    // number extends boolean ? never : number -> number
    // string extends boolean ? never : string -> string
    // boolean extends boolean ? never : boolean -> never
    // 因此,Example 类型结果为 string | number
    
    
  2. extends关键字在【泛型约束】中的使用

    限制泛型参数的类型范围

    //T 必须是一个具有 length 属性的类型。
    function logLength<T extends { length: number }>(item: T): void {
      console.log(item.length);
    }
    
    logLength("hello"); // 合法,因为字符串有 length 属性
    logLength([1, 2, 3]); // 合法,因为数组有 length 属性
    logLength({ length: 10 }); // 合法,因为对象有 length 属性
    logLength(123); // 错误,因为数字没有 length 属性
    

keyof

是类型操作符,用于获取某个类型的所有键名并构成联合类型

  1. 基本用法

    interface Person {
      name: string;
      age: number;
    }
    // 使用 keyof 获取 Person 类型的所有键名
    type PersonKeys = keyof Person; // "name" | "age"
    
  2. 在【泛型约束】中的使用

    interface Person {
      name: string
      age: number
    }
    const p: Person = {
      name: 'ym',
      age: 120
    }
    // K extends keyof T 表示泛型参数 K 必须是 T 类型的键名之一。
    function getValueOfKey<T, K extends keyof T>(obj: T, key: K): void {
      console.log(obj[key])
    }
    
    getValueOfKey(p, 'name')
    getValueOfKey(p, 'sex') //Argument of type '"sex"' is not assignable to parameter of type 'keyof Person'.
    
    
  3. 【keyof】结合【in】的使用

    例:对类型 T 的每一个属性,都创建一个同名的可选属性,其类型与 T 中对应属性的类型相同。

    interface Person {
      name: string
      age: number
    }
    
    type CustomPartial<T> = {
      [key in keyof T]?: T[key]
    }
    type Person2 = CustomPartial<Person>
    
    /**
     * type Person2 = {
        name?: string | undefined;
        age?: number | undefined;
    }
    

    [key in keyof T]?: T[key]

    • keyof T:keyof操作符获取到类型T的所有键名,并生成一个联合类型。此处生成 'name'|'age'

    • [key in keyof T]:这是一个映射类型语法,通过【in】遍历联合类型,并将每个键名映射到一个新的属性

      此key是临时变量,代表联合类型中的每个成员

    • T[key]:这是【索引类型查询】,表示取出类型T中key属性的类型

      如 key为name时,T[‘name’]就是string

范型

基本使用

动态类型,把类型当做一个变量,通过 <> 传入

  1. 范型函数

    function fn<T>(a: T, b: T): Array<T> {
      return [a, b]
    }
    fn<number>(1, 2)
    
    function fn<T, U>(a: T, b: U): Array<T | U> {
      return [a, b]
    }
    fn(1, '2')
    
    interface Data {
      code: number
      msg: string
    }
    const obj = {
      fn<T>(): Promise<T> {
        return new Promise((resolve, reject) => {
          resolve(JSON.parse('{"code":"0","msg":"success"}'))
        })
      }
    }
    obj.fn<Data>().then(res => {
      console.log(res)
    })
    
  2. 范型接口

    interface O<T> {
      msg: T
    }
    let obj: O<string> = {
      msg: 'hahha'
    }
    
  3. 范型type

    type t<T> = number | string | T
    let a: t<boolean> = true
    

范型约束

extends

范型工具

Readonly

所有属性 只读

interface Person {
  name: string
  age: number
  sex: string
}
type Person2 = Readonly<Person>

实现:

interface Person {
  name: string
  age: number
  sex: string
}

type CustomReadonly<T> = {
  readonly [key in keyof T]: T[key]
}
type Person2 = CustomReadonly<Person>

Partial

所有属性 可选

interface Person {
  name: string
  age: number
  sex: string
}
type Person2 = Partial<Person>

实现:

interface Person {
  name: string
  age: number
  sex: string
}
type CustomPartial<T> = {
  [p in keyof T]?: T[p]
}
type Person2 = CustomPartial<Person>

Required

所有属性 必选

interface Person {
  name?: string
  age?: number
  sex?: string
}
type Person2 = Required<Person>

实现:

interface Person {
  name?: string
  age?: number
  sex?: string
}
type CustomRequired<T> = {
  [p in keyof T]-?: T[p]
}
type Person2 = CustomRequired<Person>

Pick

提取部分属性

Pick 是 TypeScript 中的一个内置的工具类型,它可以实现从一个已有的类型中挑选出一部分属性,生成一个新的子类型。

interface Person {
  name: string
  age: number
  sex: string
}
type Person2 = Pick<Person, 'name' | 'age'>

实现:

interface Person {
  name: string
  age: number
  sex: string
}

type CustomPick<T, K extends keyof T> = {
  [p in K]: T[p]
}
type Person2 = CustomPick<Person, 'name' | 'age'>

Exclude

排除type中的类型

Exclude<T, U> 是 TypeScript 中的一个内置工具类型,用于从一个联合类型 T 中把符合 U 的成员删除,生成一个新的类型。

type T = string | number | boolean
type T2 = Exclude<T, boolean> //type T2 = string | number

实现:

type T = string | number | boolean

type CustomExclude<T, K> = T extends K ? never : T
type T2 = CustomExclude<T, boolean>

Extract

取共同的类型

type A = number | string | boolean
type B = string | boolean
type C = Extract<A, B>//type C = string | boolean

实现:

type A = number | string | boolean
type B = string | boolean

type CustomExclude<T, K> = T extends K ? T : never
type C = CustomExclude<A, B> //type C = string | number

Omit

排除interface中的属性

Omit 也是 TypeScript 内置的工具类型,和 Pick 相反,Omit 用于从一个已有的类型中删除某些属性,来生成一个新的属性

interface Person {
  name: string
  age: number
  sex: string
}
type Person2 = Omit<Person, 'name' | 'age'>
/**
 * type Person2 = {
    sex: string;
}
 */
  • 实现方式一:借助【Pick 和 Exclude】

    interface Person {
      name: string
      age: number
      sex: string
    }
    type CustomOmit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>
    type Person2 = CustomOmit<Person, 'name' | 'age'>
    
  • 实现方式二:借助【Exclude】

    interface Person {
      name: string
      age: number
      sex: string
    }
    type CustomOmit<T, K extends keyof T> = {
      [key in Exclude<keyof T, K>]: T[key]
    }
    type Person2 = CustomOmit<Person, 'name' | 'age'>
    
  • 实现方式三:不借助【Pick 或 Exclude】

    interface Person {
      name: string
      age: number
      sex: string
    }
    type CustomOmit<T, K extends keyof T> = {
      [key in keyof T as key extends K ? never : key]: T[key]
    }
    type Person2 = CustomOmit<Person, 'name' | 'age'>
    

NonNullable

从type 中排除掉 null 和 undefined

type A = string | number | null | undefined
type B = NonNullable<A>

实现:

type A = string | number | null | undefined

type CustomNonNullable<T> = T extends null | undefined ? never : T
type B = CustomNonNullable<A>

Record

约束对象的key和value

type Key = 'name' | 'age'
type Value = number | string
let obj: Record<Key, Value> = {
  name: 'ym',
  age: 120
}

实现:

type Key = 'name' | 'age'
type Value = number | string

type ObjKey = keyof any // type ObjKey = string | number | symbol
type CustomRecord<K extends ObjKey, V> = {
  [p in K]: V
}
let obj2: CustomRecord<Key, Value> = {
  name: 'ym',
  age: 120
}

ReturnType

获取函数返回值类型

const fn = () => '123'
type res = ReturnType<typeof fn>

实现:

type CustomReturnType<F extends Function> = F extends (...args: any[]) => infer Res ? Res : never
type res2 = CustomReturnType<typeof fn>

infer

infer用来推导范型参数

infer声明只能出现在extends子语句中

interface User {
  name: string
  age: number
}

type PromiseType = Promise<User>
type GetPromiseType<T> = T extends Promise<infer U> ? U : T
type T = GetPromiseType<PromiseType> //type T = User

联合类型、交叉类型

  1. 联合类型|

    通过管道符|将变量设置多种类型

    let arr: (number | string | boolean)[] = [1, '2', true]
    
  2. 交叉类型 &

    interface A {
      name: string
    }
    interface B {
      age: number
    }
    let user: A & B = {
      name: 'ym',
      age: 120
    }
    

类型断言

两种写法

变量 as 类型

<类型>变量

类型断言只能够「欺骗」TypeScript 编译器,无法避免运行时的错误,反而滥用类型断言可能会导致运行时错误

function fn(num: number | string): void {
  console.log((num as string).length)
  console.log((<string>num).length)
}
fn('123')

类型别名 type

type S = string
let str: S = '123'

type和interface的区别

  • interface使用extends实现继承;type使用交叉类型

    interface A {
      name: string
    }
    interface B extends A {
      age: number
    }
    
    type C = {
      name: string
    }
    type D = {
      age: number
    } & C
    
  • type中可以写联合类型;interface只能在内部属性上写联合类型

    interface A {
      name: string | number
    }
    
    type B = string | number
    
  • 重名的interface 类型会合并;重名的type会报错

类型推断

  • 当没有给出变量的类型时,ts编译器会利用类型推断来推断类型

    var num=2 //var num: number
    num='123'//编译错误 不能将类型“string”分配给类型“number”。
    
  • 如果由于缺乏声明而不能推断出类型,那么此变量的类型为any类型

    var a //var a: any
    a=1
    a='123'
    

tsconfig.json

tsc --init命令会生成tsconfig.json文件

tsc -W 监视该文件夹下的所有ts文件的变化,自动编译该文件夹下的所有ts文件

// tsconfig.json文件是ts编译器的配置文件,ts编译器可以根据配置进行编译
  {
    // 编译器选项
    "compilerOptions":{
      "target":"es6",//指定ts被编译为es的版本
      "module":"es6",// 指定要使用的模块化规范
      // "lib": ["es6","DOM"],// 指定项目中要使用的库,一般不配置
      "outDir": "./dist",// 用于指定ts编译为js后js文件的存放目录
      // "outFile": "./dist/app.js",// 将编译后的js代码放到一个文件中,此时"module":"system",或"module":"amd"
      "allowJs": false,// 编译js文件?
      "checkJs": false,// 检查js代码是否符合规范?
      "removeComments": true,// 移除注释?
      "noEmit": false,// 不生成编译后的文件?
      "noEmitOnError": false,// 当有错误时不生成编译后的文件? 
      "alwaysStrict": true,// 使用严格模式?,启用后,编译后的js文件会"use strict";
      "noImplicitAny": true,// 不允许隐式的any?
      "noImplicitThis": true,// 不允许不明确类型的this?
      "strictNullChecks": true,// 严格检查空值?
      "strict": true,// 所有严格检查的总开关
    },
    // "include":[]用来指定哪些ts文件需要被编译
    // ** 表示任意目录
    // *  表示任意文件
    "include": [
      "./src/**/*"
    ],
    // "exclude":[]用来指定不需要被编译的ts文件
    // 默认值为"node_modules","bower_components", "jspm_packages"
    "exclude": [
      "node_modules",
      "bower_components",
      "jspm_packages"
    ],
    // 继承,相当于引入某个文件
    // "extends": "",

    // files指定要编译的具体ts文件
    // "files": []
  }

声明文件 xxx.d.ts

declare

当使用第三方库时,需要引用它的声明文件,才能获得对应的代码补全、接口提示等功能

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值