抽象类
- 一个基类(父类)的一些方法无法确定具体的行为,而是由继承的子类去实现。
- 比如组件化的 React:
class MyComponent extends Component {
constructor(props) {
super(props);
this.state = {}
}
render() {
}
}
- 根据上面代码,我们可以大致设计如下类结构
- 每个组件都一个 props 属性,可以通过构造函数进行初始化,由父级定义
- 每个组件都一个 state 属性,由父级定义
- 每个组件都必须有一个 render 的方法
class Component<T1, T2> {
public state: T2;
constructor(public props: T1) {
}
render(): string {
}
}
interface IMyComponentProps {
title: string;
}
interface IMyComponentState {
val: number;
}
class MyComponent extends Component<IMyComponentProps, IMyComponentState> {
constructor(props: IMyComponentProps) {
super(props);
this.state = { val: 1 }
}
render() {
this.props.title;
this.state.val;
return `<div>组件</div>`;
}
}
- 上面的代码虽然从功能上讲没什么太大问题,但是父类的 render 有点尴尬,更应该从代码层面上去约束子类必须得有 render 方法,否则编码就不能通过
abstract 关键字
- 如果一个方法没有具体的实现方法,则可以通过 abstract 关键字进行修饰
abstract class Component<T1, T2> {
public state: T2;
constructor(public props: T1)
{
}
public abstract render(): string;
}
- 使用抽象类有一个好处:
- 约定了所有继承子类的所必须实现的方法,使类的设计更加的规范
使用注意事项: 1、abstract 修饰的方法不能有方法体 2、如果一个类有抽象方法,那么该类也必须为抽象的 3、如果一个类是抽象的,那么就不能使用 new 进行实例化(因为抽象类表名该类有未实现的方法,所以不允许实例化) 4、如果一个子类继承了一个抽象类,那么该子类就必须实现抽象类中的所有抽象方法,否则该类还得声明为抽象的
类与接口
- 通过接口,可以为对象定义一种结构和契约。我还可以把接口与类进行结合,通过接口,让类去强制符合某种契约,从某个方面来说,当一个抽象类中只有抽象的时候,它就与接口没有太大区别了,这个时候,更推荐通过接口的方式来定义契约。
- 抽象类编译后还是会产生实体代码,而接口不会
- TypeScript 只支持单继承,即一个子类只能有一个父类,但是一个类可以实现过个接口
- 接口不能有实现,抽象类可以
implements
- 在一个类中使用接口并不是使用 extends 关键字,而是
implements
- 与接口类似,如果一个类 implements 了一个接口,那么就必须实现该接口中定义的契约
- 多个接口使用 , 分隔
- implements 与 extends 可同时存在
interface ILog {
getInfo(): string;
}
class MyComponent extends Component<IMyComponentProps, IMyComponentState> implements ILog {
constructor(props: IMyComponentProps) {
super(props);
this.state = { val: 1 }
}
render() {
this.props.title;
this.state.val;
return `<div>组件</div>`;
}
getInfo() {
return `组件:MyComponent,props:${this.props},state:${this.state}`;
}
}
interface ILog {
getInfo(): string;
}
interface IStorage {
save(data: string): void;
}
class MyComponent extends Component<IMyComponentProps, IMyComponentState> implements ILog, IStorage {
constructor(props: IMyComponentProps) {
super(props);
this.state = { val: 1 }
}
render() {
this.props.title;
this.state.val;
return `<div>组件</div>`; }getInfo(): string { return `组件:MyComponent,props: ${this.props},state:${this.state}`;
}
save(data: string) {
}
}
interface ILog {
getInfo(): string;
}
interface IStorage extends ILog {
save(data: string): void;
}
类与对象
- 在 TypeScript 定义一个类的时候,其实同时定义了两个不同的类型
- 类类型(构造函数类型)。TypeScript 中的类其实本质上还是一个函数,也称为构造函数,那么这个类或者构造函数本身也是有类型的,那么这个类型就是类的类型
- 对象类型。就是 new 出来的实例类型
class Person {
static type = '人';
name: string;
age: number;
gender: string;
constructor( name: string, age: number, gender: '男'|'女' = '男' ) {
this.name = name;
this.age = age;
this.gender = gender;
}
public eat(): void {
}
}
let p1 = new Person('xiaochen', 25, '男');
p1.eat();
Person.type;
- 上面例子中,有两个不同的数据
- Person 类(构造函数)
- 通过 Person 实例化出来的对象 p1
- 对应的也有两种不同的类型
- 实例的类型( Person )
- 构造函数的类型( typeof Person )
- 用接口的方式描述如下:
interface Person {
name: string;
age: number;
gender: string;
eat(): void;
}
interface PersonConstructor {
new (name: string, age: number, gender: '男'|'女'): PersonInstance;
type: string;
}
function fn1(arg: Person ) {
arg.eat();
}
fn1( new Person('', 1, '男') );
function fn2(arg: typeof Person ) {
new arg('', 1, '男');
}
fn2(Person);
|