TypeScript速览:六、多态

多态(Polymorphism)是面向对象的核心特性之一,指同一操作应用于不同对象可以有不同的效果 (解释&结果)。TS中的多态基本表现在:重载、复写、接口、枚举、联合、泛型

一、重载

先介绍函数签名,即方法名称+参数列表(类型+数量) +返回类型,一个函数的声明只需包含函数签名即可,具体实现可以后置。

重载,即同一名称不同参数列表的签名可以有不同的函数实现,与一些编程语言不同,TS对重载的支持有些烂,这些实现写在同一个函数实现中,通过联合类型类型守卫进行分类,例如:

function fun(num: number): number; 
function fun(str: string): string;

function fun(input: number | string): number | string {
    switch(typeof input) {
        case "number": 
            return input++;
            break;

        case "string":
            return input;
        }
}

fun(2066) == 2067;
fun(wind) == "wind";

但是,对于相同名称相同参数列表的签名,由于无法区分,故即使返回类型不同也不能视为重载,例如:

function fun(num: number);
function fun(num: number);
let num = fun(0); // 编译器:我哪知道你用的是哪个fun?(╬▔皿▔)╯

此时编译器会采用复写规则:

二、复写

复写,通常用于类的继承,即同一签名或成员在父类和子类可以有不同实现,后定义的成员会覆盖先前的成员,TS提供了override关键字来显式定义,例如:

class Human {
	age: number | undefined = undefined;
	reportAge(): void {
		console.log("本人今年" + <string><any>this.age + "岁。\n");
	}
}

class Woman extends Human {
	override age = -1;
	override reportAge():void {
		("A secret makes a woman woman.\n");
	}
}

TS支持虚函数的概念,但和C++不同,TS中所有类方法默认都是虚函数,不必用类似于virtual的关键字显式声明,同时,TS的虚函数需要在原处附上默认实现(即使是空的{})

此外,C++中的纯虚函数在TS有对应,即抽象函数,使用abstract关键字声明,用于标注强制子类实现的虚函数,例如:

abstract class Human {
 	abstract reportAge(): void; // 强制子类实现
 	reportGender(): void {}     // 不强制子类实现, 需要带上默认实现
}

class Woman extends Human{
	override reportAge() {    // 此段函数实现不写会报错
	console.log("A secret makes a woman woman.\n"); 
 	}
  
	override reportGender(): void {
		console.log("♀");  
	}
}

三、接口

接口是一种‌抽象类型‌,充当"契约"的角色,用于定义对象的结构和行为而不包含具体实现,TS中使用interface关键字声明(JS中没有),?表示可选内容,例如:

interface MyInterface {
	num: number;
	str?: string;
	report(num: number): void;
}

1. 合并机制

接口自带合并机制,即多次声明同一个接口会将内容合并而不是复写,但如果出现重名,方法重名会尝试重载、属性重名会直接报错,例如:

interface MyInterface {
	num: number;
	report(num: number): void;
	}
interface MyInterface { str: string; } // 合并:{ num: number; str:string; report(num: number): void; }
interface MyInterface { num: string; } // 报错
interface MyInterface { report(str: string): void; } // 重载:{ num: number; str:string; report(num: number): void; report(str: string): void; }

2.索引签名

接口允许定义索引(下标)和值的类型契约,称为索引签名的定义,例如:

interface MyInterface {
	[key: string]: number; // 索引为字符串,值为数字
}
let obj: MyInterface = {a: 1, b: 2};

交换一下键值类型,再举个栗子:

interface MyInterface {
	[key: string]: number; // 索引为数字,值为字符串
}
let obj: MyInterface = ["a", "b"]; // {0: 'a', 1: 'b'}

当存在多个索引签名时,number索引的值必须是string索引的值的子集,例如:

interface MyInterface {
	[key: string]: any;
	[key: number]: number;
}

3.应用

接口可以通过implements关键字,用于规范类,例如:

interface MyInterface {
	num: number;
	report(num: number): void;
}

class Cls implements MyInterface {
	num: number;
	report(num: number):void {
		console.log(num);
	}
}

接口也可以作为数据类型,直接生成对象,例如:

interface MyInterface {
	num: number;
	report(num: number): void;
}

var obj: MyInterface = {
	num: number = 2067,
	report(num: number):void {
		console.log(num);
	}
}

4.模块

TS通过exportimport关键字将某系列功能的封装在一个文件中,使得内外的代码互不干扰,但又通过接口彼此关联,以此增强代码的可移植性,这种方式称为模块化编程,其中一个功能的文件称为一个模块,例如在同一目录下有myModule.tsmain.ts两个文件

在myModule.ts中:

export interface myInterface {
	// ...
}

在main.ts中:

import myModule = require("./myModule");   // 方法一,导入外部文件作为模块(.ts可以省略)
// import * as myModule from "./myModule"; // 方法二

class myClass implements myModule.myInterface {
	// ...
}

四、枚举

枚举(enum)类型用于为一组常量(通常是同一类型)命名,使代码更加清晰可读,例如:

enum Creators {
	WIND   = 2067,
	BAILEY = 8888
}
creators.WIND  == 2067;
creators[8888] == "BAILEY";

1.自动填充

和大多数语言一样,TS的枚举类型支持自动填充,即只需指定第一个值(整数类型),余下就可以依次后继,例如:

enum Week {
	SUN = 0,
  MON,
  TUE
}
week.TUE == 2;

2.优化分支

枚举类型使得switch语句更加易懂,例如:校车

enum kind {
  RAR5 = 13000,
	WINZIP = 13600
}
switch(ext) {
  case kind.RAR5:   / ... /
  case kind.WINZIP: / ... /
  default:          / ... /
}

五、联合

TypeScript使用 | 符号连接多个类型,表示变量可接受其中任一成员类型‌,其称为联合类型

1. 数据类型

联合类型最常见的应用场景,就是通过支持多类型变量,减少函数重载,例如:

function report(content: string|number): void {
    console.log("content:\t" + content);
}
report("wind");
report(2067);

该方法可以使代码能够兼容空值null,在特殊操作时提供临时空值,简化代码

2. 字面量

TS也支持联合字面量,比如boolean类型就是true|false的简写、枚举类型是各个成员的联合,再举个栗子:

type color = "red"|"green"|"blue";
let myColor: color = "green"; // 成功
let myColor: color = "cyan";  // 报错

3.联合数组

数组的声明也支持联合类型,即在保证元素类型一致时,整体的类型可以有多种选择,例如:

let arr: number[] | string[];
arr = [2, 0, 6, 7];
arr = ['w', 'i', 'n', 'd'];

六、泛型

泛型类似于”占位符”式的类型,允许在使用时让程序通过预先的设定,自行推断具体的类型,从而实现代码的复用,减少重载,可以用于函数、类、接口

泛型以<>的形式声明,<>内部的名称任取,例如:

function fun<T>(dummy: T): T {  // 指返回值与dummy类型相同
	return dummy;
}

class myClass<T> {
	constructor(input: T) {
		this.item = input;
  }
  item: T;
}

interface myInterface<T> {
  item: T;
  fun(): T;
}

也可以使用多个泛型,例如:

function fun<K, V>(key: K, value: V): {
	return (K === V); // 判断key与value的类型是否一致
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值