多态(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通过export、import关键字将某系列功能的封装在一个文件中,使得内外的代码互不干扰,但又通过接口彼此关联,以此增强代码的可移植性,这种方式称为模块化编程,其中一个功能的文件称为一个模块,例如在同一目录下有myModule.ts和main.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的类型是否一致
}

3027

被折叠的 条评论
为什么被折叠?



