TypeScript 入门合集

265 阅读6分钟

TpyeScript 语言

强类型 与 弱类型 (类型安全)

  • 强类型:强类型语言中不允许有任何的隐式类型转换

    • 优势:
      1. 错误更早暴露
      2. 代码更智能,编码更准确(智能提示
      3. 重构代码更牢靠
      4. 减少不必要的类型判断
  • 弱类型:弱类型语言中可以允许任何的隐式类型转换

    • 问题:

      // 需要等待代码具体执行时才能够发现错误
      const obj = {};
      setTimeout(()=>{
          obj.foo()
      })
      
      // 造成函数功能有可能发生改变
      function sum (a , b){
          return a + b
      }
      sum(100, 100)
      sum(100, '100')
      
      // 造成对对象索引器错误的用法
      const obj = {};
      obj[true] = 100;
      console.log(obj['true'])
      

      变量类型允许随时改变的特点,不是强弱类型的差异

动态类型 与 静态类型 (类型检查)

  • 动态类型:运行阶段才能明确变量的类型,且变量类型可以更改
  • 静态类型:变量声明式该变量的类型就是明确的,且不可更改的

TS中的原始数据类型

const a: string = 'a'

const b: number = 1

const c: boolean = true

const d: void = undefined

const e: null = null

const f: undefined = undefined

const g: symbol = Symbol()

TS中的Object类型

TS中的Object类型,并不单指普通的对象,泛指所有的非原始数据类型(对象,数组,函数)

const foo: object = function(){} // [] // {}

TS中的数组类型

// 两种不同的写法
const arr1: Array<number> = [1,2,3]

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

TS中的元组类型(Tuple Types)

元组:明确元素数量,以及每个元素类型的数组

const tuple: [number, string] = [1, 'foo']

TS中的枚举类型

// 枚举内的变量可以默认不赋值,在不赋值值得情况下,默认从0开始依次递增,若第一个值默认赋值为一个非零数字,则从这个数值开始依次递增
// 枚举内的变量若赋值为字符,则不会发生依次递增,且需要明确每一个变量的值
// 默认枚举方式会入侵到运行时的代码,即会影响编译后的代码,枚举对象会编译为一个 双向键值对函数 
// 若要避免入侵,可以使用常量枚举,在 enum 前加 变量声明关键字即可(const)
enum PostStatus {
    Draft = 0,
    UnPublished = 1,
    Published = 2
}



const post = {
    title: 'Hello TypeScript',
    content:'TypeScript is a type superset of JavaScript',
    status: PostStatus.Draft
}

TS中的函数类型

// 声明式函数

function func1(a: number, b: string): string {
    return 'func1'
}

// 可选参数写法
function func1(a: number, b: string, c?: string): string {
    return 'func1'
}

// 任意个数的参数
function func1(...rest: number[]): string {
    return 'func1'
}

// 函数表达式的方式

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

TS中的任意类型

// TS中不会对any进行类型检查,可能导致出错,所以应该尽量避免使用any类型

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

TS的隐式类型推断(Type Inference)

// 此处TS会推断age类型为number
let age = 18;


TS的类型断言(Type Assertion)

const nums = [100, 200, 300, 400]

// 此处TS会推断res的类型为 number | undefined
const res = nums.find(i => i > 0)

// 因为我们知道res一定为number类型,所以需要告诉TS,res一定为number类型。有以下两种方法

const num1 = res as number

const num2 = <number>res // 此处在使用JSX时,会产生混淆,故不推荐使用此方法

TS的接口(Interfaces)

接口是用来约定一个对象的结构。

// 定义一个接口
interface Post {
    title: string;
    content: string;
    subTitle?: string; // 表示可选成员
    readonly summary: string // readonly 表示只读成员
}

// 接口的使用
function printpost(post: Post){
    console.log(post.title)
    console.log(post.content)
}

const hello: Post = {
    title:'hello',
    contentL: 'This is a hello',
    summary: 'Title Summary'
}
// 接口可以理解为自己自定义一个类型,这个类型中规定了需要具有哪些元素,以及具体元素的类型


// 动态成员 定义的时候无法知道有哪些具体的成员

interface Cache {
    [key:string]: string
}

const cache:Cache = {
    a: 'a'
}

TS类的基本使用

TS中增强了类的使用方法


  • ts中必须先声明类的属性,若属性没有默认值,必须要构造函数中赋值
class Person {
    // ts中必须先声明类的属性,若属性没有默认值,必须要构造函数中赋值
    name: string, 
    age: number,
    construction(name: string, age: number) {
        this.name = name; 
        this.age = age;
    }
    sayHi(msg: string) : string {
        return 'hi' + msg;
    }
}

  • 类的访问修饰符

    • public 默认值,公开属性
    • private 私有属性,只能在类的内部使用,外部无法访问
    • protected 类似与 private ; 相较于 private 来说,使用 protected 的属性,是可以被继承的类访问的
      class Person {
      // ts中必须先声明类的属性,若属性没有默认值,必须要构造函数中赋值
      public name: string, 
      private age: number,
      protected gender: boolean,
      construction(name: string, age: number) {
          this.name = name; 
          this.age = age;
      }
      sayHi(msg: string) : string {
          return 'hi' + msg;
      }
    
      class Student extends Person {
          // constructor 也是可以使用修饰符修饰的
          // 此处使用private,意味着无法在外部无法使用new关键字创建Student类的属性,但是可以通过在类中实现一个静态方法创建实例
          private constructor (name: string, age: number) {
              super(name, age);
              // gender是 protected 的属性,可以在继承 Person 的类中访问
              console.log(this.gender);
          }
          
          static create(name: string, age: number){
              return new Student(name, age)
          }
      }
    
  • TS中的只读属性readonly

    class Person {
      // ts中必须先声明类的属性,若属性没有默认值,必须要构造函数中赋值
      public name: string, 
      private age: number,
      protected readonly gender: boolean, // readonly 表示只能读取,不可重新赋值
      construction(name: string, age: number) {
          this.name = name; 
          this.age = age;
      }
      sayHi(msg: string) : string {
          return 'hi' + msg;
      }
    }
    
    
  • 类与接口的比较

    • 不同的类之间可能会存在共同的特征,我们把这些共同的特征抽象出来,叫做接口
      interface Eat {
          eat (food: string) : void
      }
      interface Run {
          run (disrance: number) : void
      }
    
      // 建议一个接口只定义一种方法(能力)
      /* interface EatAndRun {
          eat (food: string) : void
          run (disrance: number) : void
      } */
    
      class Person implement Eat, Run {
          eat (food: string): void {
              console.log('优雅的吃:' + food)
          }
          run (distance: number): void {
              console.log('直立行走' + distance)
          }
      }
    
      class Animal implement Eat, Run{
          eat (food: string): void {
              console.log('没有形象的吃:' + food)
          }
          run (distance: number): void {
              console.log('爬行' + distance)
          }
      }
    
  • 抽象类 抽象类和接口类似,也是用来约束子类当中必须要有某些成员,相较于接口来说,抽象类还必须包含具体的实现,而接口只是约束不包括实现。一般较大的类,建议使用抽象类

      abstract class Animal implement Eat, Run{
          eat (food: string): void {
              console.log('没有形象的吃:' + food)
          }
          abstract run (distance: number): void
      }
    // 抽象类不能使用new关键字创建实例,只能通过继承实现子类
      class Dog extends Animal {
          run (distance: number) {
              console.log('四角爬行' + distance)
          }
      }
    
      const d = new Dog()
      d.eat('骨头')
      d.run(20)
    
  • 泛型(Generics) 泛型就是在定义类、函数、或者接口的时候,暂时不定义具体的类型,等到具体使用的时候再确认具体的类型的一种特征。意义在于极大程度的复用代码

    // 此处的T就是将来使用时传递进入的具体类型。
    function createArray<T>(length: number, value: T): T {
        return Array<T>(length).fill(value);
    }
    
    const stringArray = createdArray<string>(3, 'aaa')
    
  • 类型声明

    • 在使用第三方插件库的时候,可能会碰到未定义类型的方法(看不到类型提示),这个时候可以使用类型声明
    import { camelCase } from 'lodash';
    
    declare function camelCase (input: string): string
    // 此处声明之后就可以直接使用
    const res = camelCase('hello world')
    
    // 目前很多插件都有类型注声明文件,到时候可以去安装一下。另外,很多插件自身就包含了类型声明文件,无需单独再去安装或者声明