TypeScript

TypeScript是JavaScript超集(superset)
TypeScript=>JavaScript

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文件
    编译后的文件
    原始类型
    const a: string = 'foobar'
    const b: number = 100 // NaN Infinity
    const c: boolean = true // false
    // const d: number = null // 关闭严格模式下可以使用string,boolean在非严格模式下都可以为null
    const e: void = undefined // 一般在函数没有返回值的时候标记返回类型(只能存放null,undefined,在严格模式下只能存放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的笔记啦~~~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值