类
ts 中的类通过 class 关键字创建。
class Person {
age: number
gender = '男'
}
使用构造函数 constructor 初始化属性。
class Person2 {
age: number
gender: string
// 实例属性初始化
constructor(age: number, gender: string) {
this.age = age
this.gender = gender
}
}
const p1 = new Person2(12, '男')
console.log(p1);
类中的实例方法
class Point {
x = 10
y = 10
scale(n: number) {
this.x *= n
this.y *= n
}
}
const point = new Point()
point.scale(10)
console.log(point);
类的继承
继承使用 extends 关键字,使得子类拥有父类的属性方法(不是全部)。
class Animal {
move() {
console.log('moving along');
}
}
class Dog extends Animal {
name = '柯基'
bark() {
console.log('汪');
}
}
const dog = new Dog()
console.log(dog.name);
dog.move()
dog.bark()
类的实现
类的实现使用 implements 关键字,接口中的属性必须要在实现类中定义,方法必须要在实现类中实现。
interface Singable {
sing(): void
name: string
}
class Person3 implements Singable {
name: string = 'jack'
sing(): void {
console.log('鸡你太美~');
}
}
const p4 = new Person3()
console.log(p4.name);
p4.sing()
readonly 关键字
readonly 关键字只能用户属性中,和 Java 中的 final 关键字效果类似,也就是只读。
class Person4 {
readonly age: number = 18
constructor(age: number) {
this.age = age
}
}
当不加类型时,ts 会推断成 18 的字面量类型,只要是 readonly 修饰的属性最好是要指定其类型。
class Person5 {
readonly age = 18
}
成员可见性
目前有三种 public(默认可见性)、protected、private。上述的实例都是 public 类型,成员的属性和方法都可以访问到,这里就不再展示。
protected 受保护的属性和方法只有自己或者父类中受保护的成员,但是对实例是不可见的。
private 私有属性和方法只对自己可见。
class Animal3 {
protected move() {
console.log('moving along');
}
run() {
console.log('跑起来');
this.move()
this.__run__()
}
private __run__() {
console.log('内部辅助韩式');
}
}
class Dog3 extends Animal3 {
name = '柯基'
private bark() {
console.log('汪');
this.move()
// this.__run__() // 不能访问到父类的私有方法,报错
}
}
const d3 = new Dog3()
// d3.move() // 受保护的属性不能在实例中访问,会报错
兼容性
兼容性又有类兼容性、接口的兼容性和函数参数兼容性。
比如我们迭代数组里的元素时,用到 forEach 方法,我们在写回调时可以有三种写法。
let arr = ['a', 'b', 'c']
arr.forEach(item => {})
arr.forEach((item, index) => {})
arr.forEach((item, index, array) => {})
类兼容性
对于类和接口类型来说,y 的成员至少与 x 相同,则 x 兼容 y( 成员多的可以赋值给少)。
两个类的属性相同
class Point2 {
x: number
y: number
}
class Point2D {
x: number
y: number
}
const point2: Point2 = new Point2D()
多的给少的
class Point3D {
x: number
y: number
z: number
}
class Point2D {
x: number
y: number
}
const point3: Point2D = new Point3D()
const point4: Point3D = new Point2D() // 错误的
接口兼容性
interface Point2D {
x: number
y: number
}
interface Point3D {
x: number
y: number
z: number
}
let pp2: Point2D
let pp3: Point3D
pp2 = pp3 // 正确
pp3 = pp2 // 错误
函数参数兼容性
看对象中的属性,属性少的分配给属性多的。和上面正好反过来。
type F1 = (a: number) => void
type F2 = (a: number, b: number) => void
let f1: F1 = (a) => console.log();
let f2: F2 = f1
函数的参数为对象时,看对象中的属性,属性少的分配给属性多的。
返回值的兼容性按照其返回值本身,如果是基本类型必须要相等。如果是对象,则按照对象的兼容性规则即可。
交叉类型
将接口中定义的部分使用“&”来将两个类型合并。
interface Person7 {
name: string
say(): number
}
interface Contact {
phone: string
}
type PersonDetail = Person7 & Contact
let obj1: PersonDetail = {
name: 'jack',
phone: '114',
say() {
return 12
},
}
这种感觉和 extends 类似,但是它们还是有区别的。比如下面的代码,会报错!
interface Person7 {
name: string
say(a: number): number
}
interface Contact extends Person7 {
phone: string
say(): string
}
vscode 提示会提示接口不兼容的错误。
使用 & 就不会出问题了,vscode 提示这个合并之后该方法被重载了。
// (method) say(): number (+1 overload)
type PersonDetail = Person7 & Contact
let obj1: PersonDetail = {
name: 'jack',
phone: '114',
say() {
return 12
},
}
请勿发布违反中国大陆地区法律的言论,请勿人身攻击、谩骂、侮辱和煽动式的语言。