一. 函数类型
- 对函数增加类型
- 对函数的参数进行类型校验
- 对函数的返回值进行类型检验,也可以对函数本身来校验
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函数也是可以添加修饰符的,只是我们很少这么操作,默认情况下也是
public,protected表示不能在外界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'
}
}