Typescript 学习笔记(二)高级类型一

TypeScript高级类型

class 类

TypeScript 全面支持 ES2015 中引入的 class 关键字,并为其添加了类型注解和其他语法(比如,可见性修饰符等)

基本使用

class Person {
    age: number
    name: 'Anas'
}

const p2 = new Person()
  1. 根据 TS 中的类型推论,可以知道 Person 类的实例对象 p 的类型是 Person。
  2. TS 中的 class,不仅提供了 class 的语法功能,也作为一种类型存在。

构造函数

class Person3 {
    age: number
    gender: string
    constructor(age: number, gender: string) {
        this.age = age
        this.gender = gender
    }
}

const p3 = new Person3(18, 'male')
console.log(p3)

打印结果

Person3 { age: 18, gender: 'male' }
  1. 成员初始化(比如,age: number)后,才可以通过 this.age 来访问实例成员。
  2. 需要为构造函数指定类型注解,否则会被隐式推断为 any;构造函数不需要返回值类型

实例化方法

class Person4 {
    x = 1
    y = 2
    scale(n: number) {
        this.x *= n
        this.y *= n
    }
}

const p4 = new Person4()
p4.scale(10)
console.log(p4.x, p4.y)

方法的类型注解(参数和返回值)与函数用法相同

类的继承

extends(继承父类)
class Animal {
    move() {
        console.log('走两步')
    }
}

class Dog extends Animal{
    name = '林狗'
    bark() {
        console.log('汪汪汪')
    }
}

const dog = new Dog()
dog.move()
console.log(dog.name)

打印结果

走两步
林狗
implements(实现接口)
interface Singable {
    sing(): void
    name: string
}

class Person5 implements Singable{
    name = 'Jack'
    sing() {
        console.log('singing')
    }
}

const p5 = new Person5()
p5.sing()
  1. 通过 implements 关键字让 class 实现接口。
  2. Person 类实现接口 Singable 意味着,Person 类中必须提供 Singable 接口中指定的所有方法和属性

可见性修饰符

类成员可见性:可以使用 TS 来控制 class 的方法或属性对于 class 外的代码是否可见。
可见性修饰符包括:1 public(公有的) 2 protected(受保护的) 3 private(私有的)

public

表示公有的、公开的,公有成员可以被任何地方访问,默认可见性

class Animal {
    public move() {
        console.log('走两步')
    }
}
  1. 在类属性或方法前面添加 public 关键字,来修饰该属性或方法是共有的。
  2. 因为 public 是默认可见性,所以,可以直接省略。
protected

表示受保护的,仅对其声明所在类和子类中(非实例对象)可见

class Animal {
    protected move() {
        console.log('走两步')
    }
    run() {
        this.move()
        console.log('跑起来')
    }
}

class Dog extends Animal{
    name = '林狗'
    bark() {
        console.log('汪汪汪')
        this.move()
    }
}

const dog = new Dog()
dog.bark()
console.log(dog.name)
  1. 在类属性或方法前面添加 protected 关键字,来修饰该属性或方法是受保护的。
  2. 在子类的方法内部可以通过 this 来访问父类中受保护的成员,但是,对实例不可见
private

表示私有的,只在当前类中可见,对实例对象以及子类也是不可见的

class Animal {
    private __run__() {
        console.log('内部辅助函数')
    }

    protected move() {
        console.log('走两步')
    }
    run() {
        this.move()
        console.log('跑起来')
    }
}

class Dog extends Animal{
    name = '林狗'
    bark() {
        console.log('汪汪汪')
        this.run()
    }
}

const dog = new Dog()
dog.bark()
console.log(dog.name)
  1. 在类属性或方法前面添加 private 关键字,来修饰该属性或方法是私有的。
  2. 私有的属性或方法只在当前类中可见,对子类和实例对象也都是不可见的

只读修饰符readonly

readonly:表示只读,用来防止在构造函数之外对属性进行赋值

class Person3 {
    readonly age: number = 18
    constructor(age: number) {
        this.age = age
    }
    setAge(age:number) {
        this.age = age
    }
}

const p3 = new Person3(18)
p3.setAge(20)
console.log(p3.age)

控制台报错

11.readonly只读修饰符.ts:24:14 - error TS2540: Cannot assign to 'age' because it is a read-only property.
  1. 使用 readonly 关键字修饰该属性是只读的,注意只能修饰属性不能修饰方法。
  2. 注意:属性 age 后面的类型注解(比如,此处的 number)如果不加,则 age 的类型为 18 (字面量类型)。
  3. 接口或者 {} 表示的对象类型,也可以使用 readonly。
interface IPerson {
    readonly name: string
}

类型兼容性

两种类型系统:
1 Structural Type System(结构化类型系统)
2 Nominal Type System(标明类型系统)。
TS 采用的是结构化类型系统,也叫做 duck typing(鸭子类型),类型检查关注的是值所具有的形状。
也就是说,在结构类型系统中,如果两个对象具有相同的形状,则认为它们属于同一类型

class Point {
    x: number
    y: number
}

class Point2D {
    x: number
    y: number
}

const p4: Point = new Point2D()

对象之间的类型兼容性

Point 和 Point2D 是两个名称不同的类。 变量 p 的类型被显示标注为 Point 类型,但是,它的值却是 Point2D 的实例,并且没有类型错误。因为 TS 是结构化类型系统,只检查 Point 和 Point2D 的结构是否相同(相同,都具有 x 和 y 两个属性,属性类型也相同)。但是,如果在 Nominal Type System 中(比如,C#、Java 等),它们是不同的类,类型无法兼容

注意:在结构化类型系统中,如果两个对象具有相同的形状,则认为它们属于同一类型,这种说法并不准确。
更准确的说法:对于对象类型来说,y 的成员至少与 x 相同,则 x 兼容 y(成员多的可以赋值给少的)

class Point2D {
    x: number
    y: number
}
class Point3D {
    x: number
    y: number
    z: number
}

const p5: Point2D = new Point3D()

Point3D 的成员至少与 Point2D 相同,则 Point2D 兼容 Point3D。所以,成员多的 Point3D 可以赋值给成员少的 Point2D。

接口之间的类型兼容性

interface Point {
    x: number
    y: number
}

interface Point2D {
    x: number
    y: number
}

interface Point3D {
    x: number
    y: number
    z: number
}

class Point4D {
    x: number
    y: number
    z: number
}

let p1d: Point
let p2d: Point2D = {x: 1, y: 2}
let p3d: Point3D = {x: 1, y: 2, z: 3}

p1d = p2d
p2d = p3d

p2d = new Point4D()

函数和接口兼容性

函数之间兼容性比较复杂,需要考虑:1 参数个数 2 参数类型 3 返回值类型

  1. 参数个数,参数多的兼容参数少的(或者说,参数少的可以赋值给多的)
  2. 参数类型,相同位置的参数类型要相同(原始类型)或兼容(对象类型)
interface Point2D {
    x: number
    y: number
}

interface Point3D {
    x: number
    y: number
    z: number
}

type F1 = (a: Point2D) => void

type F2 = (b: Point3D) => void

let f1:F1 = () => {}

let f2: F2 = () => {}

f2 = f1 //不报错
f1 = f2 //报错

返回值类型,只关注返回值类型本身即可:

type F3 = () => {name: string}
type F4 = () => {name: string; age: number}

let f3: F3 = () => {return {name: ''}}
let f4: F4 = () => {return {name: '', age: 18}}

f3 = f4 //正常
f4 = f3 //报错
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值