TypeScript的函数和类

158 阅读5分钟

一. 函数类型

  • 对函数增加类型
  • 对函数的参数进行类型校验
  • 对函数的返回值进行类型检验,也可以对函数本身来校验

1.1 函数的声明方式

  • function关键字进行声明
// 限制函数参数和返回值类型
function sum(a: string, b: string):string {	// 括号后面的是返回值
    return a+b;
}
sum('a','b')
  • 表达式方式声明
type Sum = (a:string,b:string) => string;
let sum: Sum = (a:string,b:string) => {
    return a + b;
}

1.2 可选参数

使用?标记的参数,表示可选参数,即该参数可传可不传

let sum = (a:string,b?:string):string => {
    if(b){
        return a + b;
    }
    return a;
}
sum('a')	// 可选参数必须要在其他参数的最后面

1.3 默认参数

默认参数和可选参数不能作用于同一变量上

let sum = (a: string, b: string = 'b'): string => {
    return a + b;
};
sum('a'); // 默认参数必须在其他参数的最后面

1.4 剩余参数

const sum = (...args: string[]): string => {
    return args.reduce((memo, current) => memo += current, '')
}
sum('a', 'b', 'c', 'd')

1.5 函数重载

一个函数,根据参数传递的不同,实现不同的功能,ts目的就是根据不同的参数返回不同的类型

function toArray(value: number): number[]	// 重载
function toArray(value: string): string[]	// 重载
function toArray(value: number | string) {	// 真实定义
    if (typeof value == 'string') {
        return value.split('');
    } else {
        return value.toString().split('').map(item => Number(item));
    }
}
toArray(123); // 根据传入不同类型的数据 返回不同的结果
toArray('123');

二. 类

2.1 TS中定义类

实例属性需要先声明再使用,构造函数中的参数可以使用可选参数和剩余参数

class Pointer{
    x!:number; // 实例上的属性必须先声明
    y!:number;
    constructor(x:number,y?:number,...args:number[]){
        this.x = x;
        this.y = y as number;
    }
}
let p = new Pointer(100,200);

2.2 类中的修饰符

  • public修饰符:谁都可以访问的属性
class Animal {
    public name!: string; // 不写public默认也是公开的
    public age!: number;
    constructor(name: string, age: number) {
        this.name = name;
        this.age = age;
    }
}
class Cat extends Animal {
    constructor(name: string, age: number) {
        super(name, age);
        console.log(this.name,this.age); // 子类访问
    }
}
let p = new Cat('Tom', 18);
console.log(p.name,p.age); // 外界访问
  • protected修饰符:只有自己和自己的子类能够访问的属性
class Animal {
    constructor(protected name: string, protected age: number) {	// 可以通过参数属性的方式简化父类代码
        this.name = name;
        this.age = age;
    }
}
class Cat extends Animal {
    constructor(name: string, age: number) {
        super(name, age);
        console.log(this.name, this.age)	// 子类可以访问
    }
}
let p = new Cat('Tom', 18);
console.log(p.name,p.age);// 外界无法访问
  • private修饰符:仅自己能访问,其他人都访问不到
class Animal {
    constructor(private name: string, private age: number) {
        this.name = name;
        this.age = age;
    }
}
class Cat extends Animal {
    constructor(name: string, age: number) {
        super(name, age);
        console.log(this.name, this.age); // 子类无法访问
    }
}
let p = new Cat('Tom', 18); 
console.log(p.name,p.age);// 外界无法访问
  • readonly修饰符:标记为只读属性,初始化完成之后就不能被修改,如果是对象的话是可以修改属性的
class Animal {
    constructor(public readonly name: string, public age: number) {
        this.name = name;
        this.age = age;
    }
    changeName(name:string){
        this.name = name; // 报异常,仅读属性只能在constructor中被赋值
    }
}
class Cat extends Animal {
    constructor(name: string, age: number) {
        super(name, age);
    }
}
let p = new Cat('Tom', 18); 
p.changeName('Jerry');

注意:constructor函数也是可以添加修饰符的,只是我们很少这么操作,默认情况下也是publicprotected表示不能在外界new调用,private表示不能在子类中代用super

2.3 静态属性和方法

静态属性和方法是可以被子类继承的

class Animal {
    static type = '哺乳动物'; // 静态属性 es7 语法
    static getName() { 		// 静态方法
        return '动物类';
    }
    private _name: string = 'Tom';

    get name() { // 属性访问器
        return this._name;
    }
    set name(name: string) {
        this._name = name;
    }
}
let animal = new Animal();
console.log(animal.name);

2.4 Super属性

  • super 默认在构造函数中和静态方法中都指向自己的父类
  • 在原型方法中super指向父类的原型
class Animal {
    say(message:string){
        console.log(message);
    } 
    static getType(){
        return '动物'
    }
}
class Cat extends Animal {
    say(){ 	// 原型方法中的super指代的是父类的原型
        super.say('喵喵喵~');
    }
    static getType(){ // 静态方法中的super指代的是父类
        return super.getType()
    }
}
let cat = new Cat();
console.log(Cat.getType())

原型属性可以通过属性访问器的方式来实现

三. 类的装饰器

装饰器是一个实验性语法,后面可能会有改动,它的作用就是用来拓展类中的属性和方法,不能用于修饰函数,是因为函数有变量提升的问题(装饰器本质就是一个函数)

3.1 装饰类

function addSay(target:any){
    target.prototype.say = function(){console.log('say')}
}

@addSay
class Person {
    say!:Function
}
let person = new Person
person.say();

3.2 装饰类中属性

装饰属性可以对属性的内容进行改写,装饰的是实例属性则target指向类的原型、装饰的是静态属性则target指向类本身

function toUpperCase(target:any,key:string){ // target => 类的原型, key就是修饰的属性
    let value = target[key]; 
    Object.defineProperty(target,key,{
        get(){
            return value.toUpperCase();
        },
        set(newValue){
            value = newValue
        }
    })
}
function double(target: any, key: string) {// target => 类
    let value = target[key];
    Object.defineProperty(target, key, {
        get() {
            return value * 2;
        },
        set(newValue) {value = newValue}
    })
}
class Person {
    @toUpperCase
    name: string = 'Lucky7'
	@double
    static age: number = 10;
    getName() {
        return this.name;
    }
}
let person = new Person();
console.log(person.getName(),Person.age)

3.3 修饰类中的方法

function noEnum(target:any,key:string,descriptor:PropertyDescriptor){
    console.log(descriptor)
    descriptor.enumerable = false;
}
class Person {
    @toUpperCase
    name: string = 'Lucky7'
    @double
    static age: number = 10;
    @noEnum
    getName() {
        return this.name;
    }
}
let person = new Person();
console.log(person); // getName 不可枚举

3.4 修饰参数

function addPrefix(target:any,key:string,paramIndex:number){
    console.log(target,key,paramIndex); // Person.prototype getName  0 
}
class Person {
    @toUpperCase
    name: string = 'Lucky7'
    @double
    static age: number = 10;
    prefix!:string
    @noEnum
    getName(@addPrefix prefix:string) {
        return this.name;
    }
}

四. 抽象类

抽象类无法被实例化,只能被继承,抽象方法不能在抽象类中实现,只能在抽象类的具体子类中实现,而且必须实现。

abstract class Animal{
    name!:string;
    abstract speak():void
}
class Cat extends Animal {
    speak(){
        console.log('猫猫叫');
    }
}
class Dog extends Animal{
    speak():string{
        console.log('汪汪叫');
        return 'wangwang'
    }
}