一、类的基本使用
1.定义
class Greeter {
greeting: string;
constructor(message: string) {
this.greeting = message;
}
greet() {
return "Hello, " + this.greeting;
}
}
let greeter = new Greeter("world");
这个类有三个成员:一个greeting属性,一个构造函数,一个greet方法,我们通过this访问类的成员。
最后通过new构造了一个类的实例。
这个代码编译成 js 代码就是如下:
var Greeter = /** @class */ (function () {
function Greeter(message) {
this.greeting = message;
}
Greeter.prototype.greet = function () {
return "Hello, " + this.greeting;
};
return Greeter;
}());
var greeter = new Greeter("world");
2.继承
在 Typescript 中使用extends关键字来定义类的继承:
class Father{
fatherName: string = 'fatherName';
name: string; // 自己、自己的子类、自己的孙子类都能访问
age: number; // 自己和自己的子类能访问,其他类不能访问
money: number; // 只有自己能访问,子类和其他类不能访问
constructor(name: string, age: number, money: number){
this.name = name
this.age = age
this.money = money
}
getName():string{
return this.name
}
toString(){
console.log('Father')
}
}
class Child extends Father{
childName: string = 'childName';
constructor(name: string, age: number, money: number){
super(name, age, money)
}
desc(){
console.log(this.name, this.age)
}
toString(){ // 子类和父类有重名方法时,子类会覆盖父类
console.log('Child')
}
}
let child = new Child('yf', 10, 11)
console.log(child.name)
Child 通过 extends 继承了 Father,并且在Child 的constructor中调用了super()方法,他会执行基类的构造函数,而且是在访问this的属性之前调用 super() 方法,这是Typescript 继承的关键,这样Child的实例就会继承Father 的所有能够被继承的属性和方法(有些类的修饰符修饰的属性不能被继承,我们后面会说到)。
二、类的修饰符
1.公共,私有与受保护的修饰符
(1)public
通过public 修饰符指定的成员是在任何地方都可见的,也就说他自己、自己的子类、自己的孙子类都能访问到,在Typescript 中 成员都是默认为 public 的。
class Father{
public name: string; // 自己、自己的子类、自己的孙子类都能访问
constructor(name: string, age: number, money: number){
this.name = name
}
getName():string{
return this.name
}
toString(){
console.log('Father')
}
}
class Child extends Father{
constructor(name: string, age: number, money: number){
super(name)
}
}
let child = new Child('yf')
console.log(child.name) // yf
上面定义的public类通过子类继承之后,子类的实例也能访问到。
(2)private
private 私有的,他修饰的成员只能由他自己访问,子类和其他类都不能访问。
class Father{
public name: string; // 自己、自己的子类、自己的孙子类都能访问
private money: number; // 只有自己能访问,子类和其他类不能访问
constructor(name: string, money: number){
this.name = name
this.money = money
}
getName():string{
return this.name
}
toString(){
console.log('Father')
}
}
const father = new Father('leah', 10);
console.log(father.money) // Property 'money' is private and only accessible within class 'Father'.ts(2341)
class Child extends Father{
constructor(name: string, money: number){
super(name, money)
}
desc(){
console.log(this.name, this.money) // Property 'money' is private and only accessible within class 'Father'.
console.log(this.name)
}
toString(){ // 子类和父类有重名方法时,子类会覆盖父类
console.log('Child')
}
}
let child = new Child('yf', 11)
console.log(child.money) // Property 'money' is private and only accessible within class 'Father'.ts(2341)
通过上面的例子可以看到,private 修饰的成员只money能在Father 这个类里面调用,不能在Father类的实例以及子类中调用,调用就会报错 Property ‘money’ is private and only accessible within class ‘Father’.ts(2341)。
(3)protected
protected 修饰的成员只能被自己和自己的子类访问,其他类不能访问。
class Father{
static fatherName: string = 'fatherName';
public name: string; // 自己、自己的子类、自己的孙子类都能访问
protected age: number; // 自己和自己的子类能访问,其他类不能访问
private money: number; // 只有自己能访问,子类和其他类不能访问
constructor(name: string, age: number, money: number){
this.name = name
this.age = age
this.money = money
}
getName():string{
return this.name
}
toString(){
console.log('Father')
}
}
const father = new Father('leah', 20, 10);
console.log(father.money) // Property 'money' is private and only accessible within class 'Father'.ts(2341)
console.log(father.age) // Property 'age' is protected and only accessible within class 'Father' and its subclasses.ts(2445)
class Child extends Father{
static childName: string = 'childName';
constructor(name: string, age: number, money: number){
super(name, age, money)
}
desc(){
// console.log(this.name, this.age, this.money) // Property 'money' is private and only accessible within class 'Father'.
console.log(this.name, this.age)
}
toString(){ // 子类和父类有重名方法时,子类会覆盖父类
console.log('Child')
}
}
Child.fatherName; // 子类继承了父类的静态方法
Child.childName;
let child = new Child('yf', 10, 11)
console.log(child.money) // Property 'money' is private and only accessible within class 'Father'.ts(2341)
console.log(child.age) // Property 'age' is protected and only accessible within class 'Father' and its subclasses.ts(2445)
age 被 protected修饰之后,就只能在他的父类和子类中访问,不能在 父类的实例和子类的实例中访问,访问就会报错 Property ‘age’ is protected and only accessible within class ‘Father’ and its subclasses.ts(2445)
protected 还可以用来修饰 constructor 构造函数,被protected 指定的constructor只能被子类继承,不能用来创建实例。
class Test {
protected constructor(){
}
}
const t = new Test() // Constructor of class 'Test' is protected and only accessible within the class declaration.ts(2674)
class ChildTest extends Test{
constructor(){
super()
}
}
const Ct = new ChildTest()
2.readonly
readonly关键字将属性设置为只读的。 只读属性必须在声明时或构造函数里被初始化。
class Father{
static fatherName: string = 'fatherName';
public name: string; // 自己、自己的子类、自己的孙子类都能访问
protected age: number; // 自己和自己的子类能访问,其他类不能访问
private money: number; // 只有自己能访问,子类和其他类不能访问
readonly hight: number;
constructor(name: string, age: number, money: number, hight: number){
this.name = name
this.age = age
this.money = money
this.hight = hight
}
getName():string{
return this.name
}
toString(){
console.log('Father')
}
}
const father = new Father('leah', 20, 10, 150);
三、类的属性
1.参数属性
在上面我们先是通过修饰符初始化了一个属性,然后在构造函数里用接收的参数对属性进行赋值,这个过程可以用参数属性进行简化,就是在构造函数的参数前面加上访问修饰符。
class Father{
constructor(name: string, protected age: number, private money: number, readonly hight: number){
this.name = name
this.age = age
this.money = money
this.hight = hight
}
getName():string{
return this.name
}
toString(){
console.log('Father')
}
}
2.静态属性
静态属性通过 static 关键字来指定,被指定的这个成员不会被实例继承,而是直接通过类来调用.
class Father{
static fatherName: string = 'fatherName';
constructor(name: string, protected age: number, private money: number, readonly height: number){
this.name = name
this.age = age
this.money = money
this.height = height
}
}
const father = new Father('leah', 20, 10, 150);
console.log(father.fatherName) // Property 'fatherName' does not exist on type 'Father'. Did you mean to access the static member 'Father.fatherName' instead?ts(2576)
console.log(Father.fatherName)
父类的静态属性/方法,可以被子类继承
class Father{
static fatherName: string = 'fatherName';
constructor(name: string, protected age: number, private money: number, readonly height: number){
this.name = name
this.age = age
this.money = money
this.height = height
}
}
const father = new Father('leah', 20, 10, 150);
console.log(father.fatherName) // Property 'fatherName' does not exist on type 'Father'. Did you mean to access the static member 'Father.fatherName' instead?ts(2576)
console.log(Father.fatherName)
class Child extends Father{
static childName: string = 'childName';
constructor(name: string, age: number, money: number, height: number){
super(name, age, money, height)
}
}
console.log(Child.fatherName); // 子类继承了父类的静态方法
console.log(Child.childName);
let child = new Child('yf', 10, 11, 150)
console.log(child.fatherName) // Property 'fatherName' does not exist on type 'Child'. Did you mean to access the static member 'Child.fatherName' instead?ts(2576)
3.可选属性
可选属性表示可以传也可以不穿参数。
class Test {
name?: string;
constructor(name?: string){
this.name = name
}
}
const test1 = new Test()
const test2 = new Test('leah')
四、存取器
通过 getters/setters 来截取对对象成员的访问。 它能帮助你有效的控制对对象成员的访问。
class UserInfo {
name: string = '';
constructor(){}
get getName(){
return this.name
}
set setName(name: string){
this.name = name
}
}
五、抽象类
抽象类一般用来被其他类继承使用,而不是直接实例化使用。
使用abstract 关键字定义抽象类:
abstract class People{
constructor(public name: string){}
abstract getName(): string
}
class Student extends People{
constructor(name: string){
super(name)
this.name = name
}
getName(){
return this.name
}
}
const student = new Student('leah')
student.getName()
const people = new People() // Cannot create an instance of an abstract class.ts(2511)
在 People 类里面使用abstract 定义了一个抽象方法 getName,并且指定了这个方法的返回类型,也可以定义方法的参数类型。然后在 派生类 Student 里面实现了这个抽象方法,最后再通过Student 的实例调用这个抽象方法。
当对抽象类 People 进行实例化的时候报错了,所以抽象只能被子类继承了,实例化之后才能访问。
注意,必须是在派生类中实现了这个抽象方法的细节之后才能访问,不让不能访问。
abstract class People{
constructor(public name: string){}
abstract getName(): string
}
class Student extends People{ // Non-abstract class 'Student' does not implement inherited abstract member 'getName' from class 'People'.ts(2515)
constructor(name: string){
super(name)
this.name = name
}
// getName(){
// return this.name
// }
}
const student = new Student('leah')
student.getName()
在定义Student 类的时候报错了,抽象类里定义的抽象方法不会被子类继承,必须在在子类中实现该方法的定义。
/**
* 获取站点信息
*/
protected getSiteInfo(): SiteInfo{
return new SiteInfo({
appId: this.config.appId,
appVersion: this.config.appVersion,
version,
platform: this.platformTye,
uid: this.globalUUID,
sid: this.globalSessionId,
userId: this.config.userId,
ext: this.config.ext,
device: this.deviceInfo,
pageInfo: this.getPageInfo()
})
}
/**
* 获取页面信息
*/
protected getPageInfo(): PageInfo
在父类中定义了getPageInfo函数,我们不希望父组件去实现这个函数,而是由子组件实现,此时这种写法会报错,Function implementation is missing or not immediately following the declaration. 意思是 这个函数并没有被实现,要想不报错,只需要加个 abstract 关键字。
/**
* 获取页面信息
*/
protected abstract getPageInfo(): PageInfo
六、类与接口
1.类继承接口
interface Animal{
name: string
}
class Dog implements Animal{
// name: string // 可以这样声明也可以在构造函数中声明。
constructor(public name: string){}
}
定义一个Animal 接口,这个接口有一个 name 属性,定义的类 Dog 要继承这个接口,类继承接口必须使用 implements 关键字。(如果是类继承类、接口继承接口就直接使用extends 关键字)。类实现接口之后,必须声明接口中定义的属性以及方法。
一个类可以继承多个接口,且必须要将所有接口的所有属性和方法都实现了。
interface Animal{
name: string
}
interface Carnivore{
type: string
}
class Tiger implements Animal, Carnivore{
// name: string
// type: string
constructor(public name:string, public type:string){}
}
2.接口继承类
class Animal{
name: string;
}
interface A extends Animal{}
class B implements A{} // Property 'name' is missing in type 'B' but required in type 'Animal'.ts(2420)
class C implements A{ // 必须要将接口中包含的所有属性和方法都声明了才可以,不然编译会报错
name: string
}
七、在泛型中使用类
const create = <T>(c: { new (): T }): T => {
return new c();
};
class Info {
age: number;
}
create(Info).age;
create(Info).name; // error 类型“Info”上不存在属性“name”
创建了一个create函数,传入的参数是一个类,返回的是一个类创建的实例
参数c的类型定义中,new() 代表调用类的构造函数,他的类型也就是类创建的实例的类型
return new c() 表示使用传进来的 类 c 创建一个实例并返回。