Skip to content
大纲

接口

接口类型用于描述引用类型的结构,typescript 会对应用该接口的对象进行检测,但不会检测属性的顺序

示例

ts
interface Person {
  readonly _id: number;
  name: string;
  age?: number;
  friends: Friends;
}
interface Friends {
  [index: number]: string;
  length: number;
}

语法

  • 基本描述:使用 interface 定义一个接口
  • 只读属性:在接口的属性前添加 readonly 表示该属性仅在创建时可以修改
  • 可选属性:在接口的属性后追加 ? 号表示该属性为可选属性
  • 属性检查:默认会检测所有属性,以防拼写错误,可以使用以下方法跳过检查
    • 使用 [otherAttr: string]: any 不检测额外属性
    • 使用类型断言
    • 将对象赋值给一个变量,不对该变量进行类型检查

注意:readonly 属性值为引用类型时仅检测引用地址是否改变,不检测引用对象内容是否改变

引用类型可以描述以下结构

  • 'ArrayLike'
  • Object
  • function
  • class

描述对象

typescript 默认会进行额外属性检测以防止拼写错误,解决方法

  • 可以使用类型断言绕开检查
  • 可以声明一个未描述接口的对象通过该对象进行相应操作
  • 可以在接口中添加额外属性检测,如

示例

ts
interface Boy {
  readonly parents: Array<string>;
  [otherName: string]: any;
}
let boy: Boy = {
  parents: ["f", "m"],
};
boy.parents[0] = "fa";
boy.parents[1] = "ma";

描述函数

示例

ts
interface VerifyType {
  (val: any): boolean;
}
const isString: VerifyType = val => typeof val === "string";
const isNumber = <VerifyType>function (val) {
  return typeof val === "number";
}; //注意:该格式需要用变量存储函数

描述类

说明

  • 类通过 implements 关键字实现一个接口
  • 接口可以用于描述类的公共部分,但无法描述类的私有成员
  • 与对象不同的是,描述类的接口不会检测未在接口中定义的成员
  • 类含有静态部分和实例(原型)部分
    • 类实现一个接口时,仅对其实例部分进行类型检查
    • 类的静态部分相当于独立的函数,需要在使用的时候进行检查(constructor 函数属于类的静态部分)
  • 接口可以相互继承,且支持多继承

示例

ts
interface PersonConstructor {
  new (name: string, age: number): any;
}

interface Person {
  name: string;
  age: number;
  show(): void;
}

class Man implements Person {
  name: string;
  age: number;
  constructor(name: string, age: number) {}
  show() {}
}

function createPerson(Category: PersonConstructor, name: string, age: number) {
  return new Category(name, age);
}

const boy = createPerson(Man, "77", 7);

混合类型

接口可以描述函数及其属性

示例:

ts
interface Validator {
  (val: any): boolean;
  version: string;
  showVersion(): void;
}

const isString = <Validator>function (val) {
  return typeof val === "string";
};
isString.version = "0.1";
isString.showVersion = () => {};

接口继承类

说明

  • 接口继承类时会继承类的成员,但不包括其实现
  • 接口继承类时会继承类的 privateprotected 成员

函数

给函数添加类型说明,包括参数类型和返回值类型两个部分:

示例:

ts
// 给一个函数添加类型
function plus(x: number, y: number): number {
  return x + y;
}

// 给匿名函数添加类型
const minus: (a: number, b: number) => number = function (
  x: number,
  y: number
): number {
  return x - y;
};

// 使用推断类型,只给变量添加类型,编译器会自动辨识函数类型
const multi: (a: number, b: number) => number = function (x, y) {
  return x * y;
};

// 推断类型也会自动推断返回值类型
const division = (x: number, y: number) => x / y;

可选参数、默认参数、剩余参数

  • 使用 ? 置于参数之后表示该参数是可选的,可选参数必须置于必传参数后面
  • 支持 ES6 的默认参数值,使用 = 可以给参数赋默认值,调用时传递 undefined 会直接使用默认值
  • 支持 ES6 的剩余参数

描述 this

typescript 支持函数第一个参数为 this 用于描述该函数中的 this 指向

函数重载

js 中传递不同类型的参数,可以执行多种行为,可以使用函数重载进行描述

ts 编译器会按照函数重载定义的顺序,依次进行匹配,所以,在定义重载的时候,一定要把最精确的定义放在最前面

typescript 实现了 es6 中 class 的基本语法,同时添加了类型检测和扩展功能

  • 支持 ES6 class 语法
  • 支持访问限定符
  • 支持 readonly 修饰符
    • 只含有 get 方法而没有 set 方法的存取器自动推断为 readonly
  • 支持抽象类
  • 类可以作为接口使用或被接口继承

示例

ts
class Ex {
  static readonly version: string = "0.0.1";
  static showVersion() {
    alert(Ex.version);
  }

  private _init: boolean;
  protected readonly type: "a" | "b";

  constructor(public name: string, type = "a") {
    this.type = "a";
  }

  get init() {
    return this._init;
  }

  set init(init) {
    this._init = init;
  }

  doSomething() {}
}

访问限定符

说明:

  • public: 可被继承,可被实例访问,该描述符为默认值,可省略
  • private: 仅能在声明的类中使用,即不能被继承,不能被实例访问
  • protected: 仅能在基类(父类)及其派生类(子类)中使用,不能被实例访问

注意:

  • 基类中 protected 声明的成员在其派生类中可以被覆盖声明且不限制修饰符类型
  • 使用 protected 声明 contructor 可以声明一个必须被继承的类
  • 当比较带有 privateprotected 成员的类型时,只有当 private 成员和 protected 成员都来自相同的声明时,二者的类型才是兼容的

示例

ts
class Parent {
  private name: string;
}

class ExParent extends Parent {
  show() {}
}

class AsParent {
  private name: string;
}

let p: Parent = new Parent();
let exp: ExParent = new ExParent();
let asp: AsParent = new AsParent();

// p = asp //[ts]不能将类型“AsParent”分配给类型“Parent”。  类型具有私有属性“name”的单独声明。
p = exp; //ok

readonly 修饰符

  • 使用 readonly 关键字可以将属性设置值为只读的
  • 只读属性必须在声明时或构造函数内被初始化
  • 如果与成员描述符并用,需要置于成员描述符之后

示例

ts
class A {
  protected readonly name: string = "A";
  private readonly type: string;
  constructor(type) {
    this.type = type;
  }
}

通过参数属性简写

通过在构造函数上声明含有访问限定符(如果为公有成员 public 修饰符不可省略)的变量,ts 会自动声明同名成员并将其赋值

ts
class Person {
  constructor(public name: string, public age: number) {}
}

相当于

ts
class Person {
  name: string;
  age: number;
  constructor(name: string, age: number) {
    this.name = name;
    this.age = age;
  }
}

抽象类

  • 使用 abstract 关键字用于定义抽象类或抽象类内部抽象方法
  • 抽象类作为基于其派生类的基类使用,不能直接被实例化
  • 抽象方法只能出现在抽象类中,必须在派生类中实现

示例

ts
abstract class Klass {
  dou() {} //可以被继承的
  abstract show(); //必须在派生类中复写
}

typeof

  • 使用 let oneInstance: SomeClass 描述一个变量为指定类的实例
  • 使用 let oneClass: typeof SomeClass 描述一个类结构符合指定类的结构

泛型

泛型即参数化类型,将具体的类型参数化

  • 使用尖括号中传递类型变量对类型进行捕获
  • 在调用时指定类型或使用类型推论(即省略)

示例

ts
// 使用泛型参数名 T 对参数类型进行捕获
interface getArrEles {
  <T>(arr: T[]): T | T[];
}
const getHead: getArrEles = <T>(arr: T[]): T => arr[0];
const getTail: getArrEles = arr => arr[arr.length - 1];
const getWithoutHead: getArrEles = function <T>(arr: T[]): T[] {
  return arr.slice(1);
};
const getWithoutTail: getArrEles = function (arr) {
  return arr.slice(0, arr.length - 1);
};
function getSome<T>(arr: T[], index: number): T {
  return arr[index];
}
const getWithoutSome: <T>(arr: T[], idx: number) => T[] = (arr, index) =>
  arr.filter((ele, idx) => idx !== index);
getHead<string>(["a", "b", "c"]); //指定参数类型
getTail([1, 2, 3]); //使用类型推论

泛型接口

  • 类似于描述函数的接口,可以创建一个泛型接口描述泛型函数
  • 可以把泛型从参数仿作整个接口的参数,实现更加具体的描述

示例

ts
interface getArrEle {
  <T>(arr: T[]): T | T[];
}

interface getSpecialArrEle<T> {
  (arr: T): T;
}

const getFirst: getArrEle = arr => arr[0];
const getNumFirst: getSpecialArrEle<number> = arr => arr[0]; //指定了泛型类型

泛型类

与泛型接口类似,泛型类用于描实例部分的类型,静态属性不能使用泛型类型

示例

ts
class A<T> {
  private type: T;
  getType: () => T;
}
const a = new A<number>();

泛型约束

  • 泛型约束即对泛型类型添加更详细的描述
  • 使用接口和 extends 关键字来实现约束

示例

ts
interface HasLength {
  length: number;
}

function showLength<T extends HasLength>(arg: T) {
  console.log(arg.length);
}