TypeScript初体验(二)

1、字面量类型

代码示例:

function changeDirection(direction: 'up' | 'down' | 'left' | 'right') { }
changeDirection('left')
let age: 18 = 18
const str: 'Hello' = 'Hello'

‘Hello'就是一个字面量类型,除字符串外任意的JS字面量(比如对象、数字等)都可以作为类型使用。

使用模式:

字面量类型配合联合类型一起使用

使用场景:

用来表示一组明确的可选值列表 

优势:

相比于string类型,使用字面量类型更加精确、严谨。 

2、枚举

枚举:定义一组命名常量,枚举的功能类似于字面量类型+联合类型组合的功能,也可以表示一组明确的可选值。

解释:

1、使用enum关键字定义枚举

2、约定枚举名称,枚举中的值以大写字母开头

3、枚举中的多个值通过逗号(,)分隔

4、定义好枚举后,直接使用枚举名称作为类型注解

5、使用时类似于JS中的对象,直接通过点(.)语法访问枚举的成员

代码示例:

enum Direction { Up, Down, Left, Right }
function changeDirection(direction: Direction) { }
changeDirection(Direction.Down)

 注意:

1、枚举成员是有值的,默认为:从0开始自增的数值

2、把枚举成员的值为数字的枚举称为数字枚举

3、枚举成员的值都是字符串的枚举称为字符串枚举,需要注意的是字符串枚举没有自增长的行为,因此,字符串枚举的每个成员必须有初始值

4、也可以给枚举中的成员初始化值

代码示例:

enum Direction { Up = 10, Down = 3, Left, Right }
function changeDirection(direction: Direction) { }
changeDirection(Direction.Down)

 3、any类型(不推荐使用)

当值的类型为any时,可以对该值进行任意操作,并且不会有代码提示,即使可能存在错误

其他隐式具有any类型的情况:

1、声明变量不提供类型也不提供默认值

2、函数参数不加类型

所以,这两种情况下都应该提供类型

 代码示例:

let a
function add(num1, num2) {
    return num1+num2
}

4、typeof

在JS中是用来获取数据的类型,TS也提供了typeof操作符:可以在类型上下文中引用变量或属性的类型

解释:

1、typeof出现在类型注解的位置所处的位置就是类型上下文

2、typeof只能用来查询变量或属性的类型,无法查询其他形式的类型

代码示例:

let p = { x: 1, y: 2 }
function formatPoint(point: typeof p) { }
formatPoint({ x: 2, y: 8 })
let num: typeof p.x

 5、class类

TS中的class,不仅提供了class的语法功能,也作为一种类型存在

代码示例:

class Person{
    age: number
    gender = '男'
}
const p = new Person()
p.age
p.gender

构造函数

代码示例:

class Person2 {
    age: number
    gender: string
    constructor(age:number,gender:string) {
        this.age = age
        this.gender = gender
    }
}
const p2 = new Person2(12, '女')
console.log(p2.age,p2.gender);

解释:

1、成员初始化后(比如age: number),才可以通过this.age来访问实例成员

2、需要为构造函数指定类型注解,否则会被隐式判断为any

3、构造函数不需要返回值类型

 实例方法

代码示例:

class Point{
    x = 1
    y = 1
    scale(n: number) {
        this.x *= n
        this.y *= n
    }
}
const p3 = new Point()
p3.scale(10)
console.log(p3.x,p3.y);

解释:

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

class类的继承

类继承的两种方式:extends(继承父类)、implements(实现接口)

说明:JS中只有extends,而implements是TS提供的

extends继承代码示例:

class Animal{
    move() {
        console.log('走两步');
        
    }
}
class Dog extends Animal{
    name = '旺旺'
    bark() {
        console.log('旺旺!');
        
    }
}
const d = new Dog()
d.move()
d.bark()
console.log(d.name);

 解释:

1、通过extends关键字实现继承

2、子类继承父类,子类的实例对象就同时具有了父类和子类的所有属性和方法

 implements代码示例:

interface Singable{
    sing(): void
    name: string
}
class Person3 implements Singable{
    sing(): void {
        console.log('黑色星期五');
        
    }
    name = '张三'
}

解释:

1、通过implements关键字让class实现接口

2、Person类实现接口Singable意味着,Person类必须提供Singable接口中指定的所有方法和属性

 类成员可见性

可以通过TS来控制class的方法或属性对于class外的代码是否可见

可见性修饰符包括:

public(公有的)、protected(受保护的)、private(私有的)

1、public:公有成员可以被任何地方访问,默认可见,可以直接省略

2、protected:表示受保护的,仅对其声明所在类和子类中(非实例对象)可见,子类的内部可以通过this来访问父类中受保护的成员,但是,对实例不可见

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

 public代码示例:

class Animal {
    public move() {
        console.log('hahahha');
    }
}
class Dog extends Animal {
    bark() {
        console.log('旺旺!');
    }
}
const d = new Dog()
d.move

protected代码示例:

class Animal {
    protected move() {
        console.log('受保护');
    }
    run() {
        this.move
        console.log('okk');
    }
}
const a = new Animal()
a.run
class Dog extends Animal {
    bark() {
        console.log('旺旺!');
        this.move
    }
}
const d = new Dog()
d.run

private代码示例:

class Animal {
    private move() {
        console.log('私有的');
    }
    run() {
        this.move
    }
}
class Dog extends Animal {
    bark() {
        console.log('旺旺!');
        this.run
    }
}
const d = new Dog()

readonly只读修饰符

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

解释:

1、使用readonly关键字修饰该属性是只读的,注意只能修饰属性不能修饰方法

2、接口或者{}表示的对象类型,也可以使用readonly

 代码示例:

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

interface IPerson{
    readonly name: string
}
let obj: IPerson = {
    name:'Jack'
}
let obj2: {name: string} = {
    name: 'Jack'
}

类型兼容性

两种类型系统:

Structural Type System(结构化类型系统)和Nominal Type System(标明类型系统)

1、TS采用的是结构化类型系统,类型检查关注的是值所具有的形状

2、对于对象类型来说,成员多的可以赋值给少的

3、接口之间的兼容性,类似于class,并且,class和interface之间也可以兼容

代码示例:

class Point { x: number; y: number }
class Point2D { x: number; y: number }
const p: Point = new Point2D()

class Point3D { x: number; y: number; z: number }
const p2: Point = new Point3D()

接口兼容性代码示例:

interface Point { x: number; y: number }
class Point4D { x: number; y: number; z: number }
let p1: Point
p1 = new Point4D

函数之间的兼容性

需要考虑:参数个数、参数类型、返回值类型

1、参数个数,参数多的兼容参数少的(或者说:参数少的可以赋值给参数多的)

2、参数类型,相同位置的参数类型要相同(原始类型)或兼容(对象类型)

3、返回值类型,只关注返回值类型本身即可,如果返回值类型是原始类型,此时两个类型要相同;如果返回值类型是对象类型,此时成员多的可以赋值给成员少的

 参数个数代码示例:

type F1 = (a: number) => void
type F2 = (a: number, b: number) => void
let f1: F1
let f2: F2 
//@ts-ignore
f2 = f1

注意:

我也不是很清楚为什么我写的f2=f1会有校验报错(在赋值前使用了变量f1),可以在该语句上方加一个忽略ts校验的一个注释://@ts-ignore

这样就不会飘红色波浪线了

如果添加了这个注释,那么如果下面那段代码真的有bug也是不会提示的

 参数类型代码示例:

type F3 = (a: number) => string
type F4 = (a: number) => string
let f3: F3
let f4: F4
f4=f3

返回值类型代码示例:

type F5 = () => { name: string }
type F6 = () => { name: string; age: number }
let f5: F5
let f6: F6
f5 = f6

你可能感兴趣的:(typescript,前端,javascript)