一介*书生
愿你熬过苦难,依旧努力生活。

前言:TS简介相关介绍就不一一赘述,网上自行按照需求搜索查阅即可

1.TypeScript 的静态类型

TypeScript 的一个最主要特点就是可以定义静态类型,英文是 Static Typing。那到底是什么意思那?太复杂的概念性东西这里就不讲了,你可以简单的理解“静态类型”为,就是你一旦定义了,就不可以再改变了。比如你是男人就是男人,一辈子都要作男人;是女人就是女人,一辈子都是女人。这个事不可以改变!呃....好像现在也可以随便变来变去啊,这里说的是正常情况。但是它还有一些特性,这个并不像表面的那么简单。现在我们就来学习。

const count:number = 313(此时,count的值就被指定类型为number,如果是其他类型就会报错提醒)

1-1、自定义静态类型

interface YiHuanhuan {
    name: string;
    age: number;
  }
// 需要注意的是,这时候定义的变量也必须具有name和age属性了
const yihuanhuan: YiHuanhuan = {
    name: "易欢欢",
    age: 18,
  };

1-2、TypeScript 基础静态类型和对象类型


在 TypeScript 静态类型分为两种,一种是基础静态类型,一种是对象类型,这两种都经常使用,非常重要,我们先来看一下什么是基础静态类型。
基础静态类型:非常简单,只要在声明变量的后边加一个:号,然后加上对应的类型(类似这样常用的基础类型还有,最常用的如,null,undefinde,symbol,booleanvoid等
const name1:null = null
对象类型:对象类型见名就知,自定义的类型是一个对象,对象类型也可以是数组,类、函数等...

1、自定义的类型是一个对象

const yihuanhuan1: {
    name: string,
    age: number,
  } = {
    name: "易欢欢1",
    age: 18,
  };
console.log(yihuanhuan1.name);

2、类型必须是字符串数组,如果数组里面不为字符串,那么就会报错提示

const yihuanhuan2: String[] = ["谢大脚", "刘英", "小红"];

3、必须是一个Person类对应的对象才可以

class Person {}
const yihuanhuan3: Person = new Person();()

4、还可以定义一个函数类型,并确定返回值

const yihuanhuan4: () => string = () => {
    return "大脚";
};

2.TypeScript 中的类型注释和类型推断

let count1: number;
count1 = 123;
这段代码就是类型注解,意思是显示的告诉代码,我们的count1变量就是一个数字类型,这就叫做类型注解
let countInference = 123;
这段代码,没有写类型,但是把鼠标放上变量,就会提示改变量为number,这个自动推断的过程就是类型推断
工作中的潜规则就是:
  • 如果 TS 能够自动分析变量类型, 我们就什么也不需要做了
  • 如果 TS 无法分析变量类型的话, 我们就需要使用类型注解
不用写类型注解的例子:
const one = 12;
const two = 2;
const three = one + two;
必须写类型注解的例子
function getTotal(one:number, two:number) {
    return one + two;
}
const total = getTotal(1, 2);
此时,如果不写明两个参数的类型,那么如果不是number类型,就会出现逻辑错误,故此时类型注解必不可少,同时由函数的输入类型可以直接推断出total类型,total就不必须写注解

3.TypeScript 函数参数和返回类型定义

function getTotal(one:number, two:number) {
    return one + two;
}
const total = getTotal(1, 2);
上述代码,仔细会发现其中的坑,就是我们并没有定义getTotal的返回值类型,虽然TypeScript可以自己推断出返回值是number类型。
但是如果这时候我们的代码写错了,比如写成了下面这个样子:
function getTotal(one:number, two:number) {
    return one + two + ‘’;
}
const total = getTotal(1, 2);
这样返回的total的类型就变量,如果此时total在指定了类型,此时就会报错,故,代码就不严谨,函数的返回值类型就显得极为重要
function getTotal1(one: number, two: number): number {
    return one + two;
  }
const total1 = getTotal1(1, 2);

3-1、void无返回值类型:

有时候函数是没有返回值的,比如现在定义一个sayHello的函数,这个函数只是简单的terminal打印,并没有返回值,就可以给他一个类型注解void,代表没有任何返回值
function sayHello(): void {
  console.log("hello world");
}

3-2、never类型:

如果一个函数是永远也执行不完的,就可以定义返回值为never,那什么样的函数是永远也执行不完的那?我们先来写一个这样的函数(比如执行执行的时候,抛出了异常,这时候就无法执行完了)。
function errorFuntion(): never {
  throw new Error();
  console.log("Hello World");
}
还有一种是一直循环,也是我们常说的死循环,这样也运行不完,比如下面的代码:
function forNever(): never {
    while (true) {}
    console.log("Hello JSPang");
}

4.数组类型的定义

简单数组类型:

const numberArr = [1, 2, 3];

const stringArr: string[] = ["a", "b", "c"];

const numberArr: number[] = [1, 2, 3];

const undefinedArr: undefined[] = [undefined, undefined];

数组中如果有多类型:

const arr: (number | string)[] = [1, "string", 2];

数组中的对象类型定义:

const yihuanhuan5: {name: string, age: Number }[] = [ { name: "刘英", age: 18 }, { name: "谢大脚", age: 28 }, ]
这种形式看起来比较麻烦,而且如果有同样类型的数组,写代码也比较麻烦,TypeScript 为我们准备了一个概念,叫做类型别名
定义别名的时候要以type关键字开始,现在定义一个Lady的别名
type Lady = { name: string, age: Number };

const yihuanhuan5: Lady[] = [ { name: "刘英", age: 18 }, { name: "谢大脚", age: 28 }, ];

5.元组的使用和类型约束

元组:把数组中的每个元素类型的位置给固定住了,这就叫做元组

const xiaojiejie: [string, string, number] = ["dajiao", "teacher", 28];

const xiaojiejies: [string, string, number][] = [ ["dajiao", "teacher", 28], ["liuying", "teacher", 18], ["cuihua", "teacher", 25], ];等价于

const xiaojiejies: {string, string, number}[] = [ ["dajiao", "teacher", 28], ["liuying", "teacher", 18], ["cuihua", "teacher", 25], ];

目前元组用的较少,因为其完全可以用对象类型代替

6.interface接口

TypeScript的核心原则之一是对值所具有的结构进行类型检查,在TypeScript里,接口的作用就是为这些类型命名和为你的代码或第三方代码定义契约

我们可以把重复的类型注解,定义成统一的接口

interface Girl {
    name: string;
    age: number;
    bust: number;
}
const fun1 = (yihuanhuan6:Girl) => {
    console.log(yihuanhuan6.name, 'yihuanhuan6.name')
    console.log(yihuanhuan6.age, 'yihuanhuan6.age')
    console.log(yihuanhuan6.bust, 'yihuanhuan6.bust')
}
const girls = {
    name: 'test1',
    age: 18,
    bust: 23
}
fun1(girls)

接口和类型别名的区别:

6-1、写法区别

类型别名实例:
type Lady = { name: string, age: Number };

const yihuanhuan5: Lady[] = [ { name: "刘英", age: 18 }, { name: "谢大脚", age: 28 }, ];

接口实例:

interface Lady {

  name: string;

  age: Number

};

const yihuanhuan5: Lady[] = [ { name: "刘英", age: 18 }, { name: "谢大脚", age: 28 }, ];

6-2、类型别名可以直接给类型,而接口必须代表对象

type Girl1 = stirng;

6-3、接口的非必选项得定义(接口的一些特性,类别别名没有)

定义的方式是在冒号“:”前面加“?”

interface Girl {
    name: string;
    age?: number;
    bust: number;

}
const fun1 = (yihuanhuan6:Girl) => {
    console.log(yihuanhuan6.name, 'yihuanhuan6.name')
    if(yihuanhuan6.age){
        console.log(yihuanhuan6.age, 'yihuanhuan6.age')
    }
    console.log(yihuanhuan6.bust, 'yihuanhuan6.bust')
}

6-4、接口允许加入任意值

interface Girl {
    name: string;
    age?: number;
    bust: number;
    [propname: string]: any;
}
这个的意思是,属性的名字是字符串类型,属性的值可以是任何类型
实例如下:
const fun1 = (yihuanhuan6:Girl) => {
    console.log(yihuanhuan6.name, 'yihuanhuan6.name')
    if(yihuanhuan6.age){
        console.log(yihuanhuan6.age, 'yihuanhuan6.age')
    }
    console.log(yihuanhuan6.bust, 'yihuanhuan6.bust')
    yihuanhuan6.sex && console.log("性别是:"+yihuanhuan6.sex)
}
const girls = {
    name: 'test1',
    // age: 18,
    bust: 23,
    sex:'女'
}
fun1(girls)

6-5、接口里的方法

接口里不仅可以存属性,还可以存方法

interface Girl {
    name: string;
    age?: number;
    bust: number;
    [propname: string]: any;
    say(): string;
}

6-6、接口和类的约束

interface Girl {
    name: string;
    age?: number;
    bust: number;
    [propname: string]: any;
    say(): string;
}
class Yihuanhuan implements Girl {
    name = "易欢欢";
    age = 12;
    bust = 34;
    sex = '女';
    say(){
        return '12313'
    }
}

6-7、接口之间的继承

接口也可以用于继承的,比如你新写一个Teacher接口,继承于Girl 接口,一个接口可以继承多个接口,创建出多个接口的合成接口。

interface Girl {
    name: string;
    age?: number;
    bust: number;
    [propname: string]: any;
    say(): string;
}
interface Yi extends Girl {
      teach(): string;
}
class Yihuanhuan1 implements Yi {
    name = "易欢欢";
    age = 12;
    bust = 34;
    sex = '女';
    say(){
        return '12313'
    };
    teach(): string {
        return '我在教书'
    }
}
子接口继承父接口,那么子接口就拥有了父接口的访问父接口所有公用属性和方法的能力,同时还可以自己新定义一些属性和方法

6-8、接口继承类

当接口继承了一个类类型时,它会继承类的成员但不包括其实现。 就好像接口声明了所有类中存在的成员,但并没有提供具体实现一样。 接口同样会继承到类的private和protected成员。
这意味着当你创建了一个接口继承了一个拥有私有或受保护的成员的类时,这个接口类型只能被这个类或其子类所实现(implement)。
举个栗子:
class Control {
    private state: any;
}
interface SelectableControl extends Control {
    select(): void;
}
class Button extends Control implements SelectableControl {
    select() { }
}
class TextBox extends Control {
    select() { }
}
// 错误:“Image”类型缺少“state”属性。
class Image implements SelectableControl {
    select() { }
}

7.类的概念和使用

7-1、类的基本使用:

class Lady {

  content = "Hi,赛高";

  sayHello() {

    return this.content;

  }

}

const goddess = new Lady();

console.log(goddess.sayHello());

7-2、类的继承

TypeScrip 的继承和ES6中的继承是一样的,关键字也是extends,子类继承父类,那么子类就拥有了访问父类所有公用属性和方法的能力

class Lady {
    content = "Hi,lisa";
    sayHello() {
      return this.content;
    }
  }
class lisa1 extends Lady {
    sayLove() {
        return "I love you";
    }
}
  const goddess = new lisa1();
  console.log(goddess.sayHello());
  console.log(goddess.sayLove());

7-3、类的重写

重写就是子类可以重新编写父类里边的代码

class XiaoJieJie extends Lady {

  sayLove() {

    return "I love you!";

  }

  sayHello() {

    return "Hi , honey!";

  }

}

7-4、super关键字使用

当我们在继承父类的时候,在子类里面还想用到父类中的一些方法,就需要用到super关键字了

  class Lady1 {
      text = "我是父亲的内容";
      sayHello(){
          return '我是父亲的方法'
      }
  }
  class Luipte extends Lady1 {
      name = '李四';
      sayHello(){
          return '我是'+this.name+',后面的内容来自我爸爸'+super.sayHello()+this.text
      }
  }
  const son1 = new Luipte()
  console.log(son1.sayHello())

7-5、typescript中类的访问类型

类的访问类型就是基于三个关键词privateprotectedpublic,也是三种访问类型,TypeScript里,成员都默认为 public

public类型:public从英文字面的解释就是公共的或者说是公众的,在程序里的意思就是允许在类的内部和外部被调用

private类型:只允许在类的内部被调用,外部不允许调用

protected类型:允许在类内及继承的子类中使用

class Person1 {
    public name:string = "";
    private ago:number = 0;
    protected text:string = "1212";
    readonly color:string ="red";
    public sayHello(){
        // 类内
        console.log(this.name +this.ago+this.text+ 'say Hello')
    }
}
//-------以下属于类的外部--------
const person = new Person1()
person.name = 'yihuanhuan.com' // 不会报错
// person.age = 12 // 会报错
// person.text = "rrrrrr" // 会报错
// person.color = "yellow" // 会报错
console.log(person.color) // 可以读取
person.sayHello()
class Son extends Person1 {
    public sayBy(){
        console.log(this.text + '121122') // 不会报错
    }
}

 7-6、类的构造函数

比如,我们在使用类,new一个实例对象的时候,想要直接通过传递参数的形式,给里面的属性赋值,此时就需要用到构造函数,关键字是constructor

class Person2{
    public name :string;
    constructor(name:string){
        this.name=name
    }
}
const person2= new Person2('易欢欢')
console.log(person2.name)
还可以简写成:
class Person3{
    constructor(public name:string){
  //这种写法就相当于你定义了一个name,然后在构造函数里进行了赋值,这是一种简化的语法,在工作中我们使用这种语法的时候会更多一些
    }
}
const person3= new Person3('周工')

7-7、继承类的构造器

在子类中使用构造函数需要用super()调用父类的构造函数
class Person4 extends Person2 {
    constructor(public age:number){
        super('周工')
    };
    sayHello(){
        console.log(this.name +'今年是'+this.age +'岁啦!')
    }
}
const person4 = new Person4(26)
person4.sayHello()
子类继承父类并有构造函数的原则,就是在子类里写构造函数时,在构造函数里访问 this的属性之前,我们 一定要调用 super(),如果需要传值,也必须进行传值操作。就是是父类没有构造函数,子类也要使用super()进行调用,否则就会报错。
这个是TypeScript强制执行的一条重要规则。

7-8、类的 Getter 和 Setter 和static(通过 Getter 和 Setter 的形式来访问和修改这个属性。)

class Person5 {
    constructor(private _age:number){}
    get age(){
        return this._age-10
    }
    set age(age:number){
      this._age=age+3
    }
}
const person5 = new Person5(28)
person5.age=25
console.log(person5.age)
学习类,都知道要想使用这个类的实例,就要先New出来(),但是有时候不想要new实例,想要直接使用类里面的方法
此时用static声明的属性和方法,不需要进行声明对象,就可以直接使用
class Person6 {
    static sayLove() {
      return "yihuanhuan";
    }
}
console.log(Person6.sayLove());
 7-9、抽象类
抽象类做为其它派生类的基类使用。 它们一般不会直接被实例化。 不同于接口,抽象类可以包含成员的实现细节。 abstract关键字是用于定义抽象类和在抽象类内部定义抽象方法。
abstract class Animal {
    abstract makeSound(): void; // 抽类型中的抽象方法不包含具体实现,在派生类中必须实现
    move(): void { // 抽象类中的普通方法可以包含具体实现
        console.log('roaming the earch...');
    }
}
抽象类中的抽象方法不包含具体实现并且必须在派生类中实现。 抽象方法的语法与接口方法相似。 两者都是定义方法签名但不包含方法体。 然而,抽象方法必须包含 abstract关键字并且可以包含访问修饰符。
abstract class Department {
  constructor(public name: string) {}
  printName(): void {
    console.log("Department name: " + this.name);
  }
  abstract printMeeting(): void; // 必须在派生类中实现
}
class AccountingDepartment extends Department {
  constructor() {
    super("Accounting and Auditing"); // 在派生类的构造函数中必须调用 super()
  }
  printMeeting(): void {
    console.log("The Accounting Department meets each Monday at 10am.");
  }
  generateReports(): void {
    console.log("Generating accounting reports...");
  }
}
let department: Department; // 允许创建一个对抽象类型的引用
department = new Department(); // 错误: 不能创建一个抽象类的实例
department = new AccountingDepartment(); // 允许对一个抽象子类进行实例化和赋值
department.printName();
department.printMeeting();
department.generateReports(); // 错误: 方法在声明的抽象类中不存在
 
 
posted on 2023-02-19 13:55  一介-_-书生  阅读(119)  评论(0编辑  收藏  举报