类与接口
类的定义
下面是使用 TS 约束属性并实例化对象
class User {
name: string;
age: number;
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
info(): string {
return `${this.name}的年龄是${this.age}`;
}
}
const A = new User('张三',12);
const B = new User('李四',18);
通过数组类型为 User,使其成员只能是 User 类型对象
const users: User[] = [A, B];
修饰符
下面我们来掌握 JS 类与 TS 结合使用
public
下面我们介绍第一个访问修饰符,public,指公开的属性或方法
- 默认情况下属性是 public,即可以在类的内外部进行修改访问。
- 不明确设置为 public,默认就是 public。
class User {
public name: string;
public age: number;
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
public info(): string {
return `${this.name}的年龄是${this.age}`;
}
}
protected
protected 修饰符指的受保护的,只允许在父类与子类使用,不允许在类的外部使用。
class User {
protected name: string;
protected age: number;
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
protected info(): string {
return `${this.name}的年龄是${this.age}`;
}
}
// 子类访问 protected 属性
class Admin extends User {
constructor(name: string, age: number) {
super(name, age);
}
public info(): string {
return `${this.name}的年龄是${this.age}`;
}
}
const A = new User("张三", 12);
A.name = "李四"; // error
private
private 修饰符值私有的,不允许在子类与类外部使用。 父类声明 private 属性或属性,子类无法访问。
子类更改父类方法或属性的访问修饰符限制。 父类 public 子类只能是 public 父类是 protected 子类可以是 protected 或 public 父类是 private 子类不能访问修改
readonly
readonly 修饰符指的只读的,不允许在类的内部与外部进行修改。
- 类似于 const 关键字
class User {
readonly name: string;
constructor(name?: string) {
this.name = name || this.name;
}
}
constructor
构造函数是初始化实例参数使用的,在 TS 中有些细节与其他程序不同 我们可以在构造函数 constructor 中定义属性,这样就不用在类中声明属性了,可以简化代码量
class User {
constructor(public name: string, public age: number) {}
info() {
return `${this.name}的年龄是${this.age}`;
}
}
static
static 用于定义静态属性或方法,属于或方法是属于构造函数的
- 静态属性是属于构造函数的,不是对象独有的,所以是所有对象共享的
- 属于类本身 可以直接通过类名直接访问
语法介绍
下面是 static 的使用语法
class User {
static name: string = "张三";
static age: number = 12;
static info() {
return `${User.name}的年龄是${User.age}`;
}
}
单例模式
当把 constructor
定义为非 public 时候,对象无法实例化。 结合 static,可以做到单例模式。
class User {
static instance: User;
protected constructor() {}
public static getInstance() {
return User.instance || (User.instance = new User());
}
}
let a = User.getInstance();
get/set
使用 get 与 set 访问器可以动态设置和获取属性
class User {
private _name;
constructor(name: string) {
this._name = name;
}
public get name() {
return this._name;
}
public set name(value) {
this._name = value;
}
}
const a = new User("张三");
a.name = "李四";
console.log(a.name);
abstract
抽象类定义使用 abstract 关键字,抽象类除了具有普通类功能外,还可以定义抽象方法。
- 抽象类不能被实例化,只能被继承。
- 父级声明 子级实现抽象方法。
- 抽象法方法只能定义不能实现,即没有函数体。
abstract class User {
abstract info(): string;
constructor(public name: string, public age: number) {
this.name = name;
this.age = age;
}
}
class Admin extends User {
constructor() {}
info(): string {
return `${this.name}的年龄是${this.age}`;
}
}
interface
接口用于描述类和对象的结构
- 使项目中不同文件使用的对象保持统一的规范
- 使用接口 ,提供规范的代码提示
抽象类
下面是抽象类与接口的结合使用 ???
interface UserInterface {
name: string;
info(): string;
}
abstract class User implements UserInterface {
info(): string;
}
class Admin extends User {
constructor(name: string) {
super(name);
}
info(): string {
return `${this.name}`;
}
}
对象
下面使用接口来约束对象
interface UserInterface {
name: string;
age: number;
isLock: boolean;
info(other: string): string;
}
const admin: UserInterface = {
name: "change",
age: 18,
isLock: false,
info(o: string) {
return `${this.name}已经${this.age}岁了,${o}`;
},
};
console.log(admin.info());
如果尝试不存在的函数或属性时,会报错 如果有额外的属性,可以使用以下方式声明接口,可以是任意的属性
interface UserInterface {
name: string;
age: number;
[key: string]: any;
}
接口的继承
接口可以通过extends
关键字继承接口
interface interface1 {
name: string;
}
interface interface2 extends interface1 {
age: number;
}
对象可以使用多个接口,多个接口用逗号隔开
interface interface1 {
name: string;
info(): string;
}
interface interface2 {
age: number;
getAge(): number;
}
class User implements interface1, interface2 {
name: string;
age: number;
getAge(): number {
return this.age;
}
info(): string {
return `${this.name}的年龄是${this.age}`;
}
}
函数
下面是函数与接口结合使用
interface UserInterface {
name: string;
age: number;
}
function getInfo(user: UserInterface): UserInterface {
return user;
}
构造函数
与构造函数的结合
interface UserInterface {
name: string;
age: number;
}
class User {
constructor(user: UserInterface) {
this.name = user.name;
this.age = user.age;
}
}
数组
对数组类型使用接口进行约束
interface UserInterface {
name: string;
age: number;
}
const admin1: UserInterface = {
name: "name1",
age: 12,
};
const admin2: UserInterface = {
name: "name2",
age: 12,
};
const admins: UserInterface[] = [admin1, admin2];
枚举
下面是使用枚举设置性别
enum Sex {
BOY:'男',
GRID:'女'
}
interface UserInterface {
name:string,
sex:SexType
}
const admin:UserInterface = {
name:'name',
sex:Sex.BOY
}
type
type 与 interface 非常相似都可以描述一个对象或函数,使用 type 用于定义类型的别名,是非常灵活的类型定义方式。
- type 可以定义基本类型别名,如联合类型、元组
- type 与 interface 都可以进行扩展
- 使用 type 比 interface 更灵活
- 如果熟悉其他编程语言,interface 会让你更亲切
- 使用类(class)是建议使用 interface,这可以与其他编程语言保持统一。
- 决定使用哪个声明方式,最终考量公司团队(个人)的规范。
基本使用
下面是使用的 type 声明对象类型
type User = {
name: string;
age: number;
};
type 声明函数的方式
type User = (name: string, age: number) => string;
const getInfo: User = (name: string, age: number) => {
return `${name}的年龄是${age}`;
};
类型别名
type 可以为 number、string、boolean、object、array、function 等类型
// 基本类型
type Name = string;
// 联合类型定义
type Age = number | string;
type User = {
isAdmin: boolean;
age: Age;
};
const a: User = {
isAdmin: true,
age: 12,
};
// 元组
const users: [User] = [a];
索引类型
type 与 interface 在索引类型上声明是相同的
type User1 = {
name: string;
age: number;
[key: string]: any;
};
interface User2 {
name: string;
age: number;
[key: string]: any;
}
声明继承
interface 会将同名的声明进行合并 合并方式
- &
- extends
type User1 = {
name: string;
};
type User2 = User1 & { age: number };
interface User3 {}
interface User4 {}
type u5 = User3 & User4;
interface User5 extends User3, User4 {}
implements
class 可以使用 implements 来实现 type 或 interface
type UserType = {
name: string;
};
class User implements UserType {
name: string = "admin";
}