一.接口interface

1.介绍

官方:
        TypeScript的核心原则之一是对值所具有的 结构进行类型检查。 它有时被称做“鸭式辨型法”或“结构性子类型化”。 在TypeScript里,接口的作用就是为这些类型命名和为你的代码或第三方代码定义契约。

  • 简单来说, 接口中可以定义属性和方法, 声明属性的类型以及方法(参数,返回值等)的类型
  • 当一个有参的函数(使用接口)被调用时,类型检查器会检查函数是否存在参数并检查参数类型是否对应,不会检查属性的顺序, 只要相应的属性存在并且类型是对的即可

2.定义   

  • 定义接口时, 使用interface关键字来修饰
  • 可选属性   ? 修饰
  • readonly 修饰只读属性
interface objType { 
    name: string, 
    age: number,
    color ?: string,  // ? 可选属性
    readonly sex ?: string,   // 只读属性readonly, 属性只有再被创建的时候才可被修改
}

function fun1(obj: objType) {
    console.log(`${obj.name}----${obj.age}`);
}

3.额外属性检查

interface SquareConfig {
    color?: string;
    width?: number;
}
function createSquare(config: SquareConfig): { color: string; area: number } {  }
let mySquare = createSquare({ colour: "red", width: 100 });
//注意传入createSquare的参数拼写为colour而不是color。 在JavaScript里,这会默默地失败。
//你可能会争辩这个程序已经正确地类型化了,因为width属性是兼容的,不存在color属性,而且额外的colour属性是无意义的。
//然而,TypeScript会认为这段代码可能存在bug。 对象字面量会被特殊对待而且会经过 额外属性检查,当将它们赋值给变量或作为参数传递的时候。 如果一个对象字面量存在任何“目标类型”不包含的属性时,你会得到一个错误

// error: 'colour' not expected in type 'SquareConfig'
let mySquare = createSquare({ colour: "red", width: 100 });

类型断言

// 绕过检查
// 1. 类型断言
const result = show({
    name: '小白',
    age: 10,
    price:1999,
    color: 'black',
    gender: 'Weizhi '
} as ObjType)
console.log(result);

索引签名

// 额外属性检查
//  对象字面量会进行额外属性检查, 非对象字面量(如: 变量)不会进行
let num:string = 'hello'
interface ObjType{
    name: string,
    age: number,
    price: number,
    color ?: string,   // 可选属性
    // 索引签名, 代表任意个属性   使用时可继续传递     属性名是string类型, 属性值可以是 any任意类型
    [prop:string]: any
}
let dogObj: ObjType = {
    name: '旺财',
    age: 3,
    price: 188,
}
// 输出狗的信息
function show(dog:ObjType): string{
    return `name=${dog.name} - age= ${dog.age} - price= ${dog.price}`
}
const res = show(dogObj)
console.log(res);
show(dogObj)  // 不会检查

4.类类型

(1)实现接口

// 接口
interface PointInter {
    currentTime: Date;
    setTime(d: Date);
}
// 类实现接口  可实现多个接口, 接口名中间,分隔
class ClsImInter implements PointInter{
    currentTime: Date;
    setTime(d: Date) {
        this.currentTime = d;
    }
    constructor(h: number, m: number) { }   // 构造器属于静态成员
}

(2)接口继承类

class Control {
    private state: any;
}
// 接口继承类
interface SelectableControl extends Control {
    select(): void;
}
// 类继承类,实现接口
class Button extends Control implements SelectableControl {
    select() { }
}
class TextBox extends Control {
    select() { }
}

二.类class

定义

class类中包含属性,fangf,构造函数...

(1)属性

类的静态属性和实例属性:

  • 实例属性: 类的实例成员, 仅当类被实例化的时候才会被初始化的属性, 访问时使用 实例名.属性名或方法名[this.属性名]
  • 静态属性: static 修饰静态成员 所有的实例用到的属性, 归类所有,不属于具体的实例, 访问时 类名.属性名或方法名, 可赋值可修改
  • 构造函数是静态成员, 归类所有, 不是实例上的,用于创建实例

(2)修饰符

public, private, protected, readonly(只读)

  • public 公共的, 可在任意位置访问其修饰的属性及方法
  • private 私有的, 只能在本类中访问, 其他类(包括子类中也不可访问), 若想在基类中使用,需写公共的方法,基类通过访问公共方法使用父类中的私有属性
  • protected 受保护的, 可在子类中访问, 通过实例不可访问

注意:

  • constructor构造函数可以被protected修饰, 但不能使用 provate 修饰
  • 子类继承时, 可以将修饰范围变大, 但不能变小, e.g父类使用public修饰, 子类继承后不能使用private修饰
//  类 class    抽象概念  作用:创建实例
 // 声明类   使用关键字class, 类名 大驼峰式命名规则
 class Personn{
     //  特征 ---- 属性(名词)
     name: string
     age: number
     gender: number   // 0 男  1女
     // 构造函数   new 创建对象时调用构造函数
     constructor(name: string, age: number, gender: number){
         this.name = name   // 当前对象的name = 传递进来的name
         this.age = age
         this.gender = gender
     }
     // 行为 ---方法(动词)
     run(){
         console.log('running');
     }
     study(){
         console.log('study!!!');
     }
 }

2.实例

// 创建实例  new一个实例对象   
// const kk = new Person()
 //  查看属性  实例名.属性
// console.log(kk.age);  // undefinded
// 使用构造函数后需要传参
const kk = new Personn('haha',20,0)
console.log(kk);  //Personn {name: 'haha', age: 20, gender: 0}

kk.name = '空空i'
kk.age = 21
kk.gender = 1
console.log(kk);  // Personn {name: '空空i', age: '21', gender: 1}

3.继承extends

  • 使用继承来扩展现有的类
  • 子类可使用父类公共的属性和方法, 也可包含自己独有的属性和方法, 也可重写父类中的方法
  • 调用super()执行基类的构造函数, 子类的构造函数内部,第一行必须写super(父类构造函数中的属性)后方可使用父类中的属性

4.存取器

  • TypeScript支持通过getters/setters来截取对对象成员的访问。有效的控制对对象成员的访问
  • 子类可通过存取器来获取和修改基类中的属性值

5.重写override

子类可以写与基类中同名方法, 对基类的方法进行修改, 当调用时, 如果子类重写了则先调子类中的

// 继承
class Animall{
    // 公有属性
    name: string
    public weight: number
    // 私有属性
    private master: string
    // 受保护的属性
    protected type: string
    // 只读属性   必须在声明时或构造函数中赋值
    readonly fullName : string = 'ahahaha'
    // 构造函数     也可使用 private 等修饰
    constructor(name: string, weight: number){
    this.name = name
        this.weight = weight
    }
    eat(){
        console.log('Animall---都会eatting!!!');
    }
    // getter 访问该方法获取私有属性 基类对象需要 通过公共方法    getter
    getMaster(): string{
        return this.master
    }
    // setter 修改私有属性    基类对象需要 通过公共方法    好处: 控制权限, 修改条件等
    setMaster(val: string){
        if(!val || val.replace(/(^\s*|\s*$)/g,'') === ''){
            this.master = val
        }
    }
}

class Dogg extends Animall{
    // name: string
    // weight: number
    color: string   // 可以在构造函数中使用 public 修饰, 相当于在类中声明了一个属性
    // 构造函数
    constructor(name: string, weight: number, color: string){
        // 使用super 子类包含了一个构造函数, 必须调用super() 他会执行基类的构造函数
        super(name,weight)
        this.color = color
    }
    // 狗特有的方法
    gatekeeper(){
        console.log('看门Dog!!!!!');
    }
    // 重写(override)  子类重写父类的方法,名字可相同, 子类实例调用时,调用的是子类的方法, 而不是父类
    eat(){
        console.log('Dog eatting --!!!==> 重写eat');
    }
}

class Catt extends Animall{
    // name: string
    // weight: number
    species: string
        // 构造函数
        constructor(name: string, weight: number, species: string){
            // 使用super 子类包含了一个构造函数, 必须调用super() 他会执行基类的构造函数
            super(name,weight)
            this.species = species
        }
    catchMouse(){
        console.log('Cat抓老鼠!!!');
    }
}

const dogg = new Dogg('ww',12,'blue')
// 调用自己独有的方法
dogg.gatekeeper()
const catt = new Catt('qqq',3,'wwww')
catt.catchMouse()
const animall = new Animall('ee',2)
animall.eat()

6.抽象类

  • 兼顾类和接口的作用, 不能创建实例, 但可以被类继承
  • 抽象类和接口中均定义方法名, 但未实现,不包含方法体
  • 子类如果继承了抽象类, 那么子类中必须实现抽象类中没有实现的抽象方法
// 抽象类 abstract
//  兼顾类和接口的作用, 不能创建实例, 但可以被类继承
// 抽象类和接口中均定义方法名, 但未实现,不包含方法体
// 子类如果继承了抽象类, 那么子类中必须实现抽象类中没有实现的抽象方法
abstract class Animal1 {
  // 构造函数     也可使用 private 等修饰
  constructor(public name: string) {}
  // 抽象方法, 没有实现的方法, 子类必须实现
  abstract sing(): void
  // 普通方法
  dance(): void {
    console.log(this.name)
  }
  public get Name(): string {
    return this.name
  }
  public set Name(v: string) {
    this.name = v
  }
}

class Dog1 extends Animal1 {
  constructor(public name: string) {
    super(name)
  }
  // 抽象基类的抽象方法必须在子类中实现
  sing(): void {
    console.log('dogsing')
  }
}

class Cat1 extends Animal1 {
  constructor(public name: string) {
    super(name)
  }
  sing(): void {
    console.log('catsing')
  }
}

const dogs1 = new Dog1('111')
dogs1.sing()
// dogs2 类型 为 Dog1 类型
let dogs2: Dog1

// 抽象类 不能创建实例
// const qq = new Animal1()
// console.log(qq);

7.类当接口使用

// 类也是一种类型,类可以被当做接口使用
// 接口可以继承类, 接口可以继承接口
class Pointt {
    x: number;
    y: number;
}
interface Point3d extends Pointt {
    z: number;
}
let point3d: Point3d = {x: 1, y: 2, z: 3};

三.函数function

1.简介

官方介绍:
函数是JavaScript应用程序的基础。 它帮助你实现抽象层,模拟类,信息隐藏和模块。 在TypeScript里,虽然已经支持类,命名空间和模块,但函数仍然是主要的定义 行为 的地方。 TypeScript为JavaScript函数添加了额外的功能,让我们可以更容易地使用。

简单来讲, 函数中主要定义行为, 是为执行特定任务的代码块。ta是特殊的对象,可以被调用,在调用时被执行。

2.函数名

TS函数可以创建具名函数(有名字的函数)和匿名函数

//有名函数
function show(){ 
     //要执行的操作
}
//匿名函数
let fun = function(){
     //要执行的操作
}
//立即执行函数   
let fn = (function(){})()
let fn = (function(){}())
//函数表达式
const add() => { }

3.指定函数类型

为函数定义类型

// 参数x,y类型为number, 函数返回值类型为number,  若在赋值语句的一边指定了类型但是另一边没有类型的话,TypeScript编译器会进行类型推断,自动识别出型
let myAdd = function(x: number, y: number): number { 
    return x + y; 
};
// 箭头函数 Void没有任何类型, 一般情况下用于函数的返回类型, 当函数没有返回值时,类型就为void
let fun2 = (msg: string, age: number) : void =>{
    // 函数也有类型, 没有返回值时,类型就为void
}
// 匿名函数, 名字为 myAdd  向函数中传递两个参数,baseValue,increment,类型均为number, 函数返回值为number   匿名函数中 x <==> baseValue, y <==> increment
let myAdd: (baseValue: number, increment: number) => number = function(x: number, y: number): number { 
    return x + y; 
};

4.参数

  • 可选参数和默认参数
  • 当函数需要传参时, 要传递的参数个数必须与函数期望参数个数保持一致
  • 参数可设置默认值
  • 参数可传可不传 ? 实现可选
  • 传递多个参数
// 无参函数
function show(){  }
// 有参函数
function show1(name:string){ }
// 可选参数 必须位于已知参数之后
function show2(age:number, name?:string) : void { }
// 参数默认值
function buildName(firstName: string, lastName = "Smith") { }
//  给参数默认值, 并且传递的参数 ? 可有可无   参数对象默认值为{}, 当函数调用未传参时,使用默认值
function show({uname = 'mm', age = 21, tel = '158'} : { uname?:string,age?:number,tel?:string} = {}){
    return `${uname}-${age}-${tel}`
}
//把所有参数收集到一个变量里
function buildName(firstName: string, ...restOfName: string[]) {
  return firstName + " " + restOfName.join(" ");
}
let employeeName = buildName("Joseph", "Samuel", "Lucas", "MacKinzie");

5.this

顶级的非方法式调用会将 this视为window。 (注意:在严格模式下,this为undefined而不是window 

四.枚举

使用枚举可以定义一些带名字的常量。 使用枚举可以清晰地表达意图或创建一组有区别的用例。 TypeScript支持数字的和基于字符串的枚举。

// enum  枚举
// enum Genderr{
//   女,
//   男,
//   未知
// }

// 字符串枚举   每个成员都必须用字符串字面量
enum Genderr {
  女 = "WOMAN",
  男 = "MAN",
  未知 = "NO"
}

interface StuType{
  name: string,
  gender: Genderr
}

const stu3:StuType = {
  name:'张三',
  // gender: 2             //  console.log(stu3.gender);   2
  gender: Genderr.女       // console.log(stu3.gender);   0
}

console.log(stu3.gender);   // WOMAN

五.泛型

//  any任意类型  使用any类型会导致这个函数可以接收任何类型的arg参数,这样就丢失了一些信息:传入的类型与返回的类型应该是相同的。如果传入一个数字,我们只知道任何类型的值都有可能被返回
// function identity(arg: any): any {
//   return arg;
// }

// 泛型
// 使返回值的类型与传入参数的类型是相同的    使用了 类型变量,它是一种特殊的变量,只用于表示类型而不是值
// 泛型函数
// P 表示类型   返回值与参数类型相同    这个函数叫做泛型,因为它可以适用于多个类型   不会丢失信息,保持准确性,传入数值类型并返回数值类型
function identity<P>(x: P): P {
  return x
}

const s1 = identity<string>('Hello,mm!!!')
const s2 = identity<number>(100)
console.log(s1) //  Hello,mm!!!
console.log(s2) //  100

// 使用泛型变量  在泛型函数中,把参数当做任意或所有类型
function identity2<P>(x: P[]): P {
  // 输出x的长度  如果x不为undefined再输出数组
  console.log(x?.length)
  return x[0]
}
identity2([1, 2, 3]) // 3

// 泛型类型
// 函数赋给变量, 指定变量类型
const fun1: <P>(x: P[]) => P = identity2
const fun2: <T>(x: T[]) => T = identity2
const fun3: { <T>(x: T[]): T } = identity2

//泛型接口
interface Type<P>{
  (x:P[]) : P
}
// 指定泛型接口类型 string
const fun4:Type<string> = identity2

// 多个类型参数
interface dumpType<P,U>{
  key:P,
  value: U
}
const obj1: dumpType<string,number> = {key:'mm',value:21}

// 泛型类
class Operation<T> {
  zeroVal : T
  add: (x:T,y:T) => T   //函数类型, 参数是T类型
}
// 创建对象
let operationObj = new Operation<number>()
operationObj.zeroVal = 0
operationObj.add = function(x,y){
  return x + y
}

// 泛型约束
// 类ObjectType中有个length属性,类型是number, 该类型是来自传递的name.length, 由于T类型不确定, 故会报错
// class ObjectType<T> {
//     length:number;
//     constructor(public name:T){
//         this.length = name.length;
//     }
// }
// 解决: 要求T具有length属性, 约束泛型
interface LengthLimit{
  length: number
}
class ObjectType<T extends LengthLimit> {
    length:number;
    constructor(public name:T){
        this.length = name.length;
    }
}
const obje1 = new ObjectType<string[]>(["1","22"])
interface OtherObjectType { length: number, val: string };
const obje2 = new ObjectType<OtherObjectType>({ length: 10, val: "hello" });

// keyof 操作符   获取某种类型所有的键, 返回类型为联合类型
interface AnimalC {
  name:string,
  age:number,
  price:number,
}
// 获取狗的名称
function getName1<T, K extends keyof T>(obj:T,key:K){
  return  obj[key];
}
getName1({
  name: "World",
  age: 18,
  price: 47
}, "name");

参考文档: https://www.tslang.cn/docs/handbook/functions.html