接口
接口类型用于描述引用类型的结构,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'
Objectfunctionclass
描述对象
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 = () => {};接口继承类
说明
- 接口继承类时会继承类的成员,但不包括其实现
- 接口继承类时会继承类的
private和protected成员
函数
给函数添加类型说明,包括参数类型和返回值类型两个部分:
示例:
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可以声明一个必须被继承的类 - 当比较带有
private或protected成员的类型时,只有当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; //okreadonly 修饰符
- 使用
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);
}