TS入门:接口、类、函数
2024年7月23日
interface
在TS
中,interface
是用来对结构和数据进行类型定义的
具体用法
ts
interface Face {
// 属性
state: string;
// 可选属性
type?: string;
// 只读属性
readonly length: number;
// 方法
callback(): void;
// 方法二
callback2: () => void;
// 可选方法
move?(): void;
// 索引签名
[attr: string]: string | (() => any);
// 函数
(...arg: any[]): void;
// 类的实例
new Point(x: number): Object;
}
interface
的继承和扩展
interface
可以使用 extends
继承接口,并且可以同时继承多个接口
ts
// interface 继承
interface A {
name: string;
index: number;
}
interface B {
callback?(): void;
}
// 同时继承A、B
interface C extends A, B {
age: number;
}
const c: C = {
name: 'test',
index: 0,
age: 33,
callback() {
return 'hello world';
}
}
// interface 扩展
interface C {
name: string;
}
interface C {
age: number;
}
const d: C = {
name: 'yux',
age: 30,
}
类
具体用法
ts
// 类
class Point {
n: number;
// 公共属性 - TS中,没有特殊标识的,默认都为公共属性
x: number;
// 使用public显式声明公共属性
public y: number;
// 只读属性 - 必须在申明时初始化赋值 或 在constructor函数里初始化赋值
// 申明时赋值
readonly a: number[] = [100, 40];
// 只读属性 - 构造函数里赋值
readonly b: number[];
// 私有属性 - 只能在类的内部使用
private z: number = 44;
// protected 可以在类和子类内部使用的私有属性
protected w: string = 'hello';
// 静态属性 - 只能类本身访问: => Point.initPoint
static initPoint: number[] = [0, 0];
// 构造函数
constructor(x: number, y: number, private u: number /* 参数属性,接受 public、private、readonly、protected,不接受 static */)) {
this.x = x;
this.y = y;
this.b = [x, y];
this.z = this.u + 1;
}
// 公共方法
getXY() {
return [this.x, this.y];
}
// 私有方法
private getW() {
return this.z;
}
// 存取器
get nPoint() {
return this.n ? this.n : 0;
}
set nPoint(value: number) {
if (value > 0) {
this.n = value;
} else {
this.n = 100;
}
}
}
const point: Point = new Point(100, 50);
console.log(point.x); // => 100
console.log(Point.initPoint); // => [0, 0]
console.log(point.a); // => [100, 40]
console.log(point.aPoint) // => 0
point.nPoint = 20;
console.log(point.aPoint) // => 20
console.log(point.initPoint); // Error,initPoint是静态属性,只能通过类来使用,不能使用实例调用
console.log(point.w); // Error, w是私有属性,只能类内部使用
point.b = [1, 1]; // => Error, b是只读属性,不能给他赋值
类的继承
ts
// 使用 extends 继承父类
class Surface extends Point {
points: number[];
constructor(x: number, y: number) {
// Surface类有构造函数,super()必须调用,实际是调用父类的构造函数
// 并且必须在当前构造函数内访问 this 之前调用super()
super(x, y, 2);
// 调用父类的方法
this.points = this.getXY();
}
// 父类定义的 protected 私有属性 可以在子类中使用
getNewPoint() {
return this.w + 1;
}
}
const surface: Surface = new Surface(22, 33);
// 调用父类的静态属性
console.log(Surface.initPoint); // => [0, 0]
抽象类和抽象方法
抽象类或抽象方法使用abstract
关键字定义。抽象类不允许实例化,且抽象方法只能在抽象类中定义。抽象类中的抽象方法不包含具体实现并且必须在派生类(子类)中实现。 抽象方法的语法与接口方法相似。 两者都是定义方法签名但不包含方法体。 然而,抽象方法必须包含 abstract
关键字并且可以包含访问修饰符。
ts
abstract class A {
name = 'yux';
abstract getName(): string; // 必须在子类中实现
}
class B extends A {
getName() {
return this.name;
}
}
const a: A = new A; // Error, 抽象类不允许实例化
const b: A = new B;
另外,当某个变量的类型是抽象类时,改抽象类的子类中实现了抽象类未定义的方法,在该变量上无法调用。
ts
abstract class A {
name = 'yux';
abstract getName(): string; // 必须在子类中实现
}
class B extends A {
getName() {
return this.name;
}
sayHello() {
return `hello ${this.name}`;
}
}
const b: A = new B;
b.getName(); // OK => yux
b.sayHello(); // Error, 方法在声明的抽象类中不存在
const c: B = new B;
c.getName(); // OK => yux
c.sayHello(); // OK => hello yux
interface 和 类
类的类型
使用implements
表示某个类
是接口
的具体实现:
ts
interface A {
name: string;
sayHello();
}
class B implements A {
name = 'yux';
sayHello() {
return `hello ${this.name}`;
}
}
TIP
接口只描述了类的公共部分,并不包含类的私有部分,所以它不会帮你检查类是否具有某些私有成员。
接口继承类
ts
class Point {
x = 0;
y = 0;
add(): number {
return this.x + this.y;
}
}
// 接口继承类
interface A extends Point {
get(): number[];
}
// 继承类Point,并且实现了接口 A
class Point2 extends Point implements A {
get() {
return [this.x, this.y];
}
}
把类当成接口使用
由于类
可以创造类型,所以可以在允许使用接口的地方使用类,从而把类
当成接口
使用。
ts
class A {
x: number;
y: number;
}
const a: A = {
x: 1,
y: 2,
}
函数
函数是JavaScript应用程序的基础。 它帮助你实现抽象层,模拟类,信息隐藏和模块。 在TypeScript里,虽然已经支持类,命名空间和模块,但函数仍然是主要的定义 行为的地方。
函数类型的定义分为两部分,一是参数类型的定义,二是返回值类型的定义,并且只有参数类型是匹配的,哪怕参数名称不匹配,也认为是有效的。
ts
// 完整定义
const add: (a: string) => void = (b: string): string => {
return `hello ${b}`;
}
// 可选参数 - 可选参数只能放在必须参数的后面
const move = (a: string, b?: string): string => `${a}${b ? b : ' hello'}`;
// 带默认值的参数
const handel = (a: string, b = 'world'): string => `${a} ${b}`;
// 剩余参数 - 必须在所有参数后面
const callback = (a: string, b: number, ...arg: (number | string)[]): void => {
xxx
}
函数的重载
在开发中,函数根据传入不同的参数而返回不同类型的数据是很常见的,方法是为同一个函数提供多个函数类型定义来进行函数重载。
ts
// 函数的重载
function xx(a: string): string;
function xx(a: number): number;
function xx(a): any {
return a;
}
const x = xx('xx'); // => OK
const w = xx(1); // => OK
const n = xx(true); // => Error
为了让编译器能够选择正确的检查类型,它与
JavaScript
里的处理流程相似。 它查找重载列表,尝试使用第一个重载定义。 如果匹配的话就使用这个。 因此,在定义重载的时候,一定要把最精确的定义放在最前面。
转载说明
本文允许全文转载,转载请注明来源: 平凡公子 - TS入门:接口、类、函数