类型别名 类型别名用来给一个类型起个新名字,类型别名常用于联合类型 字符串字面量类型 字符串字面量类型用来约束取值只能是某几个字符串中的一个 元组 数组合并了相同类型的对象,而元组(Tuple)合并了不同类型的对象 当直接对元组类型的变量进行初始化或者赋值的时候,需要提供所有元组类型中指定的项 当添加越界的元素时,它的类型会被限制为元组中每个类型的联合类型 ` 枚举 类型用于取值被限定在一定范围内…

类型别名

类型别名用来给一个类型起个新名字,类型别名常用于联合类型

type Name = string;
type NameResolver = () => string;
type NameOrResolver = Name | NameResolver;
function getName(n: NameOrResolver): Name {
  if (typeof n === 'string') {
    return n;
  } else {
    n();
    return n();
  }
}

字符串字面量类型

字符串字面量类型用来约束取值只能是某几个字符串中的一个

type EventNames = 'click' | 'scroll' | 'mousemove';
function Handle(ele: Element, event: EventNames): number {
  return 1;
}
Handle(document.getElementById('box'), 'click');

元组

数组合并了相同类型的对象,而元组(Tuple)合并了不同类型的对象

let tuple: [string, number] = ['hello', 12];
let tuple2: [string, number];
tuple2[0] = 'hello';

当直接对元组类型的变量进行初始化或者赋值的时候,需要提供所有元组类型中指定的项

当添加越界的元素时,它的类型会被限制为元组中每个类型的联合类型 `

let tuple: [string, number] = ['hello', 12];
tuple.push('world');
tuple.push(12);

枚举

类型用于取值被限定在一定范围内的场景

枚举成员会被赋值为从 0 开始递增的数字,同时也会对枚举值到枚举名进行反向映射:

enum Days {
  Sun,
  Mon,
  Tue,
  Wed,
  Thu,
  Fri,
  Sat
}
console.log(Days['Sun'] == 0);
console.log(Days[0] == 'Sun');

手动赋值

// 手动赋值
// 不要出现覆盖现象,因为覆盖ts是无法察觉到的,
// 比如下例中Sun=2,Tue已经是2了,那么编译出来Days['Tue'] == 2 , Days['Sun'] == 2
// 但是Days[2] == 'Tue',Day[2]!='Sun'
enum Days {
  Sun = 7,
  Mon = 1,
  Tue,
  Wed,
  Thu,
  Fri,
  Sat
}
console.log(Days['Sun'] == 7);
console.log(Days['Tue'] == 2);

枚举项有两种类型:常数项(constant member)和计算所得项(computed member)

// 常数项分类:https://ts.xcatliu.com/advanced/enum#chang-shu-xiang-he-ji-suan-suo-de-xiang
enum Color {
  Red,
  Blue = 'blue'.length
}
// 如果紧接在计算所得项后面的是未手动赋值的项,那么就会因为无法获取初始化而报错
// 报错
enum Color2 {
  Blue = 'blue'.length,
  Red
}
// 不报错
enum Color3 {
  Blue = 'blue'.length,
  Red = 1.5
}

常数枚举,如果包含计算成员,就会报错

const enum Direction {
  Up,
  Down,
  Left,
  Right
}
let direction = [Direction.Up, Direction.Down, Direction.Left, Direction.Right];

外部枚举

// declare 定义的类型只会用于编译时的检查,编译结果中会被删除
// 外部枚举与声明语句一样,常出现在声明文件中
// declare 和 const可以共用
declare enum Direction1 {
  Up,
  Down,
  Left,
  Right
}
declare const enum Direction2 {
  Up,
  Down,
  Left,
  Right
}
let direction1 = [Direction1.Up, Direction1.Down, Direction1.Left, Direction1.Right];
let direction2 = [Direction2.Up, Direction2.Down, Direction2.Left, Direction2.Right];

生成的 js

var direction1 = [Direction1.Up, Direction1.Down, Direction1.Left, Direction1.Right];
var direction2 = [0 /* Up */, 1 /* Down */, 2 /* Left */, 3 /* Right */];

TypeScript 可以使用三种访问修饰符(Access Modifiers),分别是 public、private 和 protected。

TypeScript 可以使用三种访问修饰符(Access Modifiers),分别是 public、private 和 protected

class Animal {
  public name;
  public constructor(name) {
    this.name = name;
  }
}
let a = new Animal('dog');
a.name = 'cat';

设置一个私有属性

class Animal {
  private name;
  public constructor(name) {
    this.name = name;
  }
}
let a = new Animal('dog');
// 报错
a.name = 'cat';

private 子类不可访问,protected 子类可以访问

class Animal {
  private name;
  protected age;
  public constructor(name) {
    this.name = name;
  }
}
class Person extends Animal {
  public constructor(name) {
    super(name);
  }
  public getAge() {
    console.log(this.age);
  }
  // 报错
  public getName() {
    console.log(this.name);
  }
}

abstract 用于定义抽象类和其中的抽象方法

// 首先,抽象类是不允许被实例化的:
abstract class Animal {
  public name: string;
  public constructor(name: string) {
    this.name = name;
  }
}

class Person extends Animal {
  public constructor(name: string) {
    super(name);
  }
  getName(): string {
    console.log(this.name);
    return this.name;
  }
}
// 报错
// let a = new Animal()
// 不报错
let p = new Person('dog');
console.log(p.name);

生成的 js

var __extends =
  (this && this.__extends) ||
  (function() {
    var extendStatics = function(d, b) {
      extendStatics =
        Object.setPrototypeOf ||
        ({ __proto__: [] } instanceof Array &&
          function(d, b) {
            d.__proto__ = b;
          }) ||
        function(d, b) {
          for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
        };
      return extendStatics(d, b);
    };
    return function(d, b) {
      extendStatics(d, b);
      function __() {
        this.constructor = d;
      }
      d.prototype = b === null ? Object.create(b) : ((__.prototype = b.prototype), new __());
    };
  })();
// abstract 用于定义抽象类和其中的抽象方法。
// 首先,抽象类是不允许被实例化的:
var Animal = /** @class */ (function() {
  function Animal(name) {
    this.name = name;
  }
  return Animal;
})();
var Person = /** @class */ (function(_super) {
  __extends(Person, _super);
  function Person(name) {
    return _super.call(this, name) || this;
  }
  Person.prototype.getName = function() {
    console.log(this.name);
    return this.name;
  };
  return Person;
})(Animal);
// 报错
// let a = new Animal()
// 不报错
var p = new Person('dog');
console.log(p.name);

类与接口

接口(Interfaces)可以用于对「对象的形状(Shape)」进行描述。接口还可以对类的一部分行为进行抽象

不同类之前可以有一些公有的特性,把这些公有的提成接口,用 implements 来实现

// 不同类之前可以有一些公有的特性,把这些公有的提成接口,用implements来实现
// 门是一个类,防盗门是门的子类,防盗门有报警,防盗门有开灯关灯
// 车是一个类,小卡车是车的子类,小卡车有报警,小卡车有开灯关灯
// 车是一个类,大卡车是车的子类,大卡车有报警,大卡车没有开灯关灯,大卡车的报警为吹笛子
// 把报警和灯提取出来,作为一个接口
// 报警接口
interface Alarm {
  alert();
}
// 开关灯接口
interface Light {
  lightOn();
  lightOff();
}
// 笛子接口
interface Flute extends Alarm {
  boast();
}

class Door {}
// 防盗门
class SecurityDoor extends Door implements Alarm, Light {
  alert() {
    console.log('防盗门报警');
  }
  lightOn() {
    console.log('防盗门选择开灯');
  }
  lightOff() {
    console.log('防盗门选择关灯');
  }
}

class Car {}
// 小卡车
class SmallCar extends Car implements Alarm, Light {
  alert() {
    console.log('小卡车报警');
  }
  lightOff() {
    console.log('小卡车选择关灯');
  }
  lightOn() {
    console.log('小卡车选择开灯');
  }
}
// 大卡车
class BigCar extends Car implements Flute {
  alert() {}
  boast() {}
}

生成的 js

var __extends =
  (this && this.__extends) ||
  (function() {
    var extendStatics = function(d, b) {
      extendStatics =
        Object.setPrototypeOf ||
        ({ __proto__: [] } instanceof Array &&
          function(d, b) {
            d.__proto__ = b;
          }) ||
        function(d, b) {
          for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
        };
      return extendStatics(d, b);
    };
    return function(d, b) {
      extendStatics(d, b);
      function __() {
        this.constructor = d;
      }
      d.prototype = b === null ? Object.create(b) : ((__.prototype = b.prototype), new __());
    };
  })();
var Door = /** @class */ (function() {
  function Door() {}
  return Door;
})();
// 防盗门
var SecurityDoor = /** @class */ (function(_super) {
  __extends(SecurityDoor, _super);
  function SecurityDoor() {
    return (_super !== null && _super.apply(this, arguments)) || this;
  }
  SecurityDoor.prototype.alert = function() {
    console.log('防盗门报警');
  };
  SecurityDoor.prototype.lightOn = function() {
    console.log('防盗门选择开灯');
  };
  SecurityDoor.prototype.lightOff = function() {
    console.log('防盗门选择关灯');
  };
  return SecurityDoor;
})(Door);
var Car = /** @class */ (function() {
  function Car() {}
  return Car;
})();
// 小卡车
var SmallCar = /** @class */ (function(_super) {
  __extends(SmallCar, _super);
  function SmallCar() {
    return (_super !== null && _super.apply(this, arguments)) || this;
  }
  SmallCar.prototype.alert = function() {
    console.log('小卡车报警');
  };
  SmallCar.prototype.lightOff = function() {
    console.log('小卡车选择关灯');
  };
  SmallCar.prototype.lightOn = function() {
    console.log('小卡车选择开灯');
  };
  return SmallCar;
})(Car);
// 大卡车
var BigCar = /** @class */ (function(_super) {
  __extends(BigCar, _super);
  function BigCar() {
    return (_super !== null && _super.apply(this, arguments)) || this;
  }
  BigCar.prototype.alert = function() {};
  BigCar.prototype.boast = function() {};
  return BigCar;
})(Car);

接口继承类

class Ponit {
  x: number;
  y: boolean;
}
interface Ponit3d extends Ponit {
  z: string;
}
let Ponit3d: Ponit3d = { x: 1, y: false, z: 'hello' };

混合类型

// 接口来定义函数的形状
interface Couter {
  (start: number): string;
  interval: number;
  reset(): void;
}
function getCouter(): Couter {
  let couter = <Couter>function(strat: number) {};
  couter.interval = 1000;
  couter.reset = function() {};
  return couter;
}
let g = getCouter();
g(10);
g.reset();
g.interval = 2000;

泛型

泛型(Generics)是指在定义函数、接口或类的时候,不预先指定具体的类型,而在使用的时候再指定类型的一种特性。

实现一个 createArray

// 没有准确的定义返回值的类型,预期数组中的每一项的类型与输入的value的类型一致
function createArray(length: number, value: any): Array<any> {
  let result = [];
  for (let i = 0; i < length; i++) {
    result[i] = value;
  }
  return result;
}
createArray(3, 'x');

泛型实现:意味着,createArray 的成员类型必须与 value 类型一致,提前定义好成员类型,如果 value 与提前定义好的类型不一致,就报错

function createArray<T>(length: number, value: T): Array<T> {
  let result: T[] = [];
  for (let i = 0; i < length; i++) {
    result[i] = value;
  }
  return result;
}
createArray<String>(3, 'x');

定义泛型的时候,可以一次定义多个类型参数

// 定义了一个swap函数,用来交还输入的元祖
function swap<T, U>(tuple: [T, U]): [U, T] {
  return [tuple[1], tuple[0]];
}
swap<string, number>(['hello', 12]);

泛型约束

// 在函数内部使用泛型的时候,事先不知道它是哪种类型,所以不能随意操作它的属性与方法
// 报错
// function login<T>(name: T): T {
//   console.log(name.length);
//   return name;
// }
// 进行泛型约束:只允许传入有length属性的变量
interface Lenghtwise {
  length: number;
}
function login2<T extends Lenghtwise>(name: T): T {
  console.log(name.length);
  return name;
}
// 报错:因为1没有长度
// login2(1);
// 不报错
login2('hello');

// 多个类型参数之前也可以互相约束
// T继承于U,保证了U上不会出现T中不存在的字段
function copy<T extends U, U>(target: T, source: U): T {
  for (let key in source) {
    target[key] = (<T>source)[key];
  }
  return target;
}
let x = { a: 1, b: 2 };
// 报错
// copy(x, { a: 10, b: '20' });
// 不报错
copy(x, { a: 10, b: 20 });

使用泛型接口来定义函数

interface CreateFn {
  <T>(length: number, value: T): Array<T>;
}
let createFn: CreateFn = function<T>(length: number, value: T): Array<T> {
  let result: T[] = [];
  for (let i = 0; i < length; i++) {
    result[i] = value;
  }
  return result;
};
createFn(3, 'x');

interface CreateFn2<T> {
  (length: number, value: T): Array<T>;
}
let createFn2: CreateFn2<number> = function<T>(length: number, value: T): Array<T> {
  let result: T[] = [];
  for (let i = 0; i < length; i++) {
    result[i] = value;
  }
  return result;
};
createFn2(3, 1);

泛型类,泛型用户类的类型定义

// 泛型参数可以选择默认值
class Class1<T = string> {
  get: T;
  add: (x: T, Y: T) => T;
}
let class1 = new Class1();
class1.get = 0 + '';
class1.add = (x, y) => x + y;

声明合并

如果定义了两个相同名字的函数、接口或类,那么它们会合并成一个类型

函数的合并

function reverse(x: number): number;
function reverse(X: string): string;
function reverse(x: number | string): number | string {
  if (typeof x == 'number') {
    return Number(
      x
        .toString()
        .split('')
        .reverse()
        .join('')
    );
  } else {
    x.split('')
      .reverse()
      .join('');
  }
}

接口的合并

// 合并的属性的类型必须是唯一的
interface Car {
  price: number;
}
interface Car {
  age: string;
}
// 相当于
// interface Car {
//   price: number;
//   weight: number;
// }

interface Bike {
  price: number;
  alert(a: string): string;
}
interface Bike {
  name: string;
  alert(a: string, b: number): number;
}
// 相当于
// interface Bike {
//   price: number;
//   name: string;
//   alert(a: string): string;
//   alert(a: string, b: number): number;
// }

暂无评论