TypeScript讲解-第三弹

115 阅读4分钟

类型断言

通过 类型断言 可以告诉编辑器: 相信我,我知道自己在干什么。类型断言好比其它语言里的类型转换,但是不进行特殊的数据检查和解构。 它没有运行时的影响,只是在编译阶段起作用。  TypeScript 会假设你,程序员,已经进行了必须的检查。

// 第一种: 尖括号 语法
let someValue: any = 'this is a string';
let strLength: number = (<string>someValue).length;
console.log('strLength', strLength);

// 第二种: as 语法
let someValue2: any = 'this is a string';
let strLength2: number = (someValue2 as string).length;
console.log('strLength2', strLength2);

类型别名

类型别名用来给一个类型起个新名字。使用 type 创建类型别名,常用于联合类型。

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

字符串字面量类型

适合用来约束取值只能是某个字符串的其中一个。注意,类型别名与字符串字面量类型都是使用 type 进行定义。

type EventNames = "Click" | "Scroll" | "MouseMove";
function handleEvent(event: EventNames) {
  console.log(event);
}
// 取值只能为 "Click" | "Scroll" | "MouseMove" 其中一个
handleEvent("Scroll");

元祖Tuple和枚举

元组类型允许表示一个已知元素数量和类型的数组,各元素的类型不必相同。 比如,你可以定义一对值分别为stringnumber类型的元组。

let tom: [string, number] = ['Tom', 25];

枚举(Enum)类型用于取值被限定在一定范围内的场景,比如一周只能有七天,颜色限定为红绿蓝等。使用 enum 关键字来定义。

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

enum Days {
  Sun,
  Mon,
  Tue,
  Wed,
  Thu,
  Fri,
  Sat,
}

console.log(Days["Sun"] === 0); // true
console.log(Days["Mon"] === 1); // true
console.log(Days["Tue"] === 2); // true
console.log(Days["Sat"] === 6); // true

console.log(Days[0] === "Sun"); // true
console.log(Days[1] === "Mon"); // true
console.log(Days[2] === "Tue"); // true
console.log(Days[6] === "Sat"); // true

手动赋值

手动赋值的枚举项会接着上一个枚举项递增。

enum Days {Sun = 7, Mon = 1, Tue, Wed, Thu, Fri, Sat};

console.log(Days["Sun"] === 7); // true
console.log(Days["Mon"] === 1); // true
console.log(Days["Tue"] === 2); // true
console.log(Days["Sat"] === 6); // true

字符串枚举

enum Person {
    name = "NAME",
    age = "AGE",
    love = "LOVE",
    hobby = "HOBBY"
}
console.log(Person.name) // NAME
console.log(Person.hobby) // HOBBY

异构枚举

enum Person {
    name = 1,
    age = 2,
    love = "LOVE",
    hobby = "HOBBY"
}
console.log(Person.name) // 1
console.log(Person.hobby) // HOBBY

常量枚举

常量枚举通过在枚举上使用 const 修饰符来定义,常量枚举不同于常规的枚举,他们会在编译阶段被删除。

const enum Size {
    WIDTH = 10,
    HEIGHT = 20
}
const area = Size.WIDTH * Size.HEIGHT

// 常量枚举成员在使用的地方会被内联进来,之所以可以这么做是因为,常量枚举不允许包含计算成员;如上例所示,在运行时是没有 Size

泛型

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

function createArray(length: number, value: any): Array<any> {
  let result = [];
  for (let i = 0; i < length; i++) {
    result[i] = value;
  }
  return result;
}
console.log(createArray(5, "A"));

这段代码编译不会报错,但是一个显而易见的缺陷是,它并没有准确的定义返回值的类型:

Array<any> 允许数组的每一项都为任意类型。但是我们预期的是,数组中每一项都应该是输入的 value 的类型。

这时候,泛型就派上用场了:

function createArray<T>(length: number, value: T): Array<T> {
  let result = [];
  for (let i = 0; i < length; i++) {
    result[i] = value;
  }
  return result;
}
console.log(createArray<string>(5, "A"));
// 也可以不指定,通过类型推论也可以自动推算出来
console.log(createArray(5, "A"));

泛型约束

在函数内部使用泛型变量的时候,由于事先不知道它是哪种类型,所以不能随意的操作它的属性或方法

function loggingIdentiy<T>(arg: T): T {
    // 编辑器提示:类型“T”上不存在属性“length”
    console.log(arg.length)
    return arg
}

上例中,泛型 T 不一定包含属性 length,所以编译的时候报错了。

这时,我们可以对泛型进行约束,只允许这个函数传入那些包含 length 属性的变量。这就是泛型约束

// string 类型中有 length 属性
function loggingIdentiy<T extends string>(arg: T): T {
  console.log(arg.length);
  return arg;
}

// 或者是继承相关的接口
interface ILength {
    length: number
}
function loggingIdentiy<T extends ILength>(arg: T): T {
  console.log(arg.length);
  return arg;
}

泛型函数接口

interface ConfigFn {
  <T>(value: T): T;
}
var getData: ConfigFn = (value) => {
  return value;
}
console.log(getData<string>('张三'))
// 提示:类型“number”的参数不能赋给类型“string”的参数
console.log(getData<string>(1)) 

泛型类

class GetMin<T>{
  arr: T[] = [];
  add(ele: T) {
    this.arr.push(ele)
  }
  min(): T {
    var min = this.arr[0];
    this.arr.forEach(value => {
      if (value < min) {
        min = value
      }
    })
    return min
  }
}
var gm1 = new GetMin<number>();
gm1.add(5)
gm1.add(2)
gm1.add(3)
gm1.add(1)
console.log(gm1.min()) // 1

var gm2 = new GetMin<string>();
gm2.add("tom");
gm2.add("jerry");
gm2.add("jack");
gm2.add("sunny");
console.log(gm2.min()) // jack

泛型参数的默认类型

在 TypeScript 2.3 以后,我们可以为泛型中的类型参数指定默认类型。当使用泛型时没有在代码中直接指定类型参数,从实际值参数中也无法推测出时,这个默认类型就会起作用

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