欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

TypeScript

程序员文章站 2022-07-14 21:04:37
...

TypeScript是JavaScript超集(superset)
TypeScript

TypeScript 安装(npm)

  1. 安装typescript依赖
    npm i typescript -D
    
    这一步安装完成之后其实就可以使用tsc命令来执行TypeScript的相关代码了
  2. 配置tsconfig.json文件
    tsc --init 
    
    生成的配置文件如下:
    {
      "compilerOptions": {
        "target": "es5", // 指定ECMAScript目标版本
        "lib": ["ES2015", "DOM"], // 使用的类库
        "module": "commonjs", // 指定模块化类型
        "declaration": true, // 生成 `.d.ts` 文件
        "sourceMap": true,  // 开启源文件映射
        "outDir": "./dist", // 编译后生成的文件目录
        "rootDir": "./src",   // 源代码所在的文件
        "strict": true // 开启严格的类型检测
      }
    }
    
  3. 将编译命令添加到package.json中
     "scripts": {
      	"build": "tsc" # 增加 ts 编译命令
      },
    
  4. 运行命令
    npm run build
    
    编译完成之后,我们可以看到目录下出现了dist目录,在该目录下生成了三个文件,一个包含代码逻辑的js文件,一个包含类型定义的interface文件,还有一个包含映射关系的map文件
    TypeScript
    原始类型
    const a: string = 'foobar'
    const b: number = 100 // NaN Infinity
    const c: boolean = true // false
    // const d: number = null // 关闭严格模式下可以使用
    const e: void = undefined
    const f: null = null;
    const g: undefined = undefined;
    const h: symbol = Symbol(); // 如果是定义target:es5则symbol会报错,因为找不到对应类型的标准库,所以要添加"lib": ["ES2015", "DOM"]
    
    以上,如果需要使用es6的特性就需要把target改成es2015,但如果这样改的话,那默认的标准库就被覆盖了,所以需要在lib中添加"lib": [“ES2015”, “DOM”], 这样就可以都找到es6和原本dom的标准库了。
    标准库就是内置对象所对应的声明
    中文错误提示
    tsc --locale zh-CN
    
    object类型
    object类型并不单指普通的对象,可以是数组也可以是函数
    const foo: object = function () {} // [] // {}
    const obj: {foo: number, bar: string} = {foo: 123, bar: 'string'}
    
    数组类型
    // 数组类型的两种表示方式
    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
    
    元组
    // 数组中元素的数据类型都一般是相同的(any[] 类型的数组可以不同),如果存储的元素数据类型不同,则需要使用元组。
    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
    
    枚举
    // 用对象模拟枚举
    // const PostStatus = {
    //   Draft: 0,
    //   Unpublished: 1,
    //   Published: 2
    // }
    
    // 标准的数字枚举
    // enum PostStatus {
    //   Draft = 0,
    //   Unpublished = 1,
    //   Published = 2
    // }
    
    // 数字枚举,枚举值自动基于前一个值自增
    // enum PostStatus {
    //   Draft = 6,
    //   Unpublished, // => 7
    //   Published // => 8
    // }
    
    // 字符串枚举
    // enum PostStatus {
    //   Draft = 'aaa',
    //   Unpublished = 'bbb',
    //   Published = 'ccc'
    // }
    
    // 常量枚举,不会侵入编译结果(不加const,则会在编译后的文件中生成一个双向的键值对对象,可以通过值找到键)
    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
    
    函数
    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'
    }
    
    any类型
    function stringify (value: any) {
      return JSON.stringify(value)
    }
    stringify('string')
    stringify(100)
    stringify(true)
    let foo: any = 'string'
    foo = 100
    foo.bar()
    // any 类型是不安全的
    
    隐式类型判断
    let age = 18 // number
    // age = 'string' // 报错,因为ts已经把age推断为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 // 推荐
    const num2 = <number>res // JSX 下不能使用,因为尖括号会和jsx里面的标签产生冲突
    // 类型断言时编译过程中的概念,当编译过后,这个断言也就不存在了
    
    接口
    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'
    })
    // 接口只是做约束所用的,实际运行过程中并没有实际的意义
    
    接口补充(可选成员,只读成员)
    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的相关语法
    class Person {
      name: string // = 'init name'
      age: number
      constructor (name: string, age: number) {
        this.name = name // 不能直接使用this,需要在类中声明(主要是为了给属性做类型的标注)  在es7标准定义的
        this.age = age
      }
      sayHi (msg: string): void {
        console.log(`I am ${this.name}, ${msg}`)
      }
    }
    
    类的访问修饰符
    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) { // 设置成private,那么这个类就不能在外部被实例化,也不能被继承
        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) // 报错,因为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
    }
    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}`)
      }
    }
    
    抽象类
    抽象类和接口有些类似,也是要约束子类当中必须要有某一个成员,但是不同于接口的是,抽象类当中可以包含一些具体的实现,而接口只能够是成员的抽象,不包含具体的实现。
    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)
    
    泛型
    在定义函数,接口类时,不定义它的类型,等到使用的时候再去定义它的类型,这样可以极大程度的复用代码
    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')
    // 泛型就是把在定义时不明确的类型变成一个参数,在使用的时候再去传递这个参数
    
    类型声明
    declare 类型声明,一个函数在定义的时候因为一些原因没有被声明,那在使用的时候就需要用declare来声明一下。这种用法时为了兼容npm中一些用js编写的模块
    declare function camelCase (input: string): string
    

以上就是TypeScript的笔记啦~~~