前言

vue3曾经公布了,ts的脚步曾经拦截不住了,还只会es6?别想了,人家都曾经在口头了,以下是ts的根本系列教程,ts的根本语法,高级语法等,以及在vue我的项目中如何利用ts,跟着我连忙撸起来吧。

根本数据类型

数字
const a: number = 3;
字符串
const b: string = "1";
数组
const c: number[] = [1, 2, 3];const d: Array<number> = [1, 3];const arr: any[] = [1, "33", true];
元组

能够为数组中的每个参数定义绝对应的类型

const e: [number, string] = [1, "ww"];
枚举
enum error {  blue = 3,  "orange",}const f: error = error.orange;console.log(f); //输入4

tips

  1. 如果未赋值的上一个值是数字那么这个未赋值的值的是上一个值的值+1
  2. 如果未赋值上一个值未赋值那么输入的就是它的下标
  3. 如果未赋值的上一个值的值是非数字,那么必须赋值
布尔类型
const g: boolean = true;
对象
const i: object = {};
undefined

罕用于组合类型

let j: number | undefined;
null
let k: null;
void

指定办法类型,示意没有返回值,办法体中不能return

function aa(): void {  console.log(1);}//如果办法有返回值,能够加上返回值的类型function bb(): number {  return 1;}
never

其余类型 (包含null和undefined)的子类型,代表从不会呈现的值

let l: never;//匿名函数并抛出异样l = (() => {  throw new Error("111");})();
任意类型

让参数能够是任何一种类型

let h: any = 1;h = true;h = "st";

函数

函数申明
function cc(): void {}
办法传参
function getUserInfo(name: string, age?: number, school: string = "清华大学") {  return `name:${name}--age:${age}--school:${school}`;}
tips: ?代表这个参数可传可不传,不传就是undefined,也可定义个默认的值
残余参数

传递多个时,如果用了残余参数,就能够把未定义的形参转换为数组。

function sum (a: number, b: number, ...arr: number[]): number {  let sum: number = a + b;  arr.forEach((element) => {    sum += element;  });  console.log(arr); [3,4,5]    return sum;}console.log(sum(1, 2, 3, 4, 5)); //15
函数重载
function reload(name: string): string;function reload(age: number): string;function reload(param: any): any {  return typeof param === "string" ? `我是:${param}` : `我的年龄:${param}`;}console.log(reload(18)); //年龄
tips: 被重载的办法,是没有办法体,能够依据参数的类型走其中一个办法并判断参数,但如果传入的参数类型不是任何被重载办法的参数类型就不容许通过。
 第 1 个重载(共 2 个),“(name: string): string”,呈现以下谬误。   类型“never[]”的参数不能赋给类型“string”的参数。 第 2 个重载(共 2 个),“(age: number): string”,呈现以下谬误。   类型“never[]”的参数不能赋给类型“number”的参数

class Person {  // 公有变量  private name: string;    // 构造函数  constructor(name: string) {    this.name = name;  }    // 获取名字  getName(): string {    return this.name;  }    // 设置名字  setName(name: string): void  {    this.name = name;  }}let p = new Person("张三");p.setName("李四");console.log(p);

继承

class Son extends Person { // 动态属性  public static age: number = 18;  // 学校  public school: string;  //构造方法  constructor(name: string, school: string) {    // 拜访派生类的构造函数中的 "this" 前,必须调用 "super",初始化父类构造函数 --并把参数传给父类    super(name);     //把传进来的school赋值给全局变量    this.school = school;  }  //静态方法  static run(name: string): string {    return `${name}在跑步,他的年龄才${this.age}`;  }}let son = new Son("王五", "清华大学");son.setName("赵六"); // 公有类也不能在子类的内部拜访,但可通过公开的办法中进行赋值和拜访console.log(son);console.log(Son.run("方七"));console.log(Son.age);

tips:

  1. public 在以后类外面,子类,类里面都能够拜访
  2. protected 在以后类和子类外部能够拜访,类内部无法访问
  3. private 在以后类外部可拜访,子类,类内部都无法访问。
  4. 属性不加修饰符,默认就是私有的 (public)

多态

通过形象办法/办法重载--实现多态--多态的作用是用来定义规范

// 形象父类abstract class Animal {  private name: string;  constructor(name: string) {    this.name = name;  }  //形象成员--办法  abstract eat(): any;  //形象成员--属性  protected abstract ages: Number;  sleep(): void {    console.log("睡觉");  }}class cat extends Animal {  ages: Number = 2;  constructor(name: string) {    super(name);  }  //非抽象类“cat”不会主动实现继承自“Animal”类的形象成员“eat”,  必须手动定义父类中的形象办法--多态  eat(): string {    return "猫吃鱼";  }  //多态  sleep(): string {    return "猫在睡觉";  }}console.log(new cat("33").sleep());

tips:

  1. 抽象类无奈实例化
  2. 非抽象类继承形象父类时不会主动实现来自父类的形象成员,必须手动定义父类中的形象成员,否则报错。
  3. 形象成员包含属性办法

接口

  在面向对象的编程中,接口是一种标准的定义,它定义了行为和动作的标准,

  在程序设计外面,接口起到一种限度和标准的作用。

  接口定义了某一批类所须要恪守的标准,接口不关怀这些类的外部状态数据,也不关怀这些类里办法的实现细节,它只规定这批类里必须提供某些办法,提供这些办法的类就能够满足理论须要。ts中的接口相似于java,同时还减少了更灵便的接口类型,包含属性、函数、可索引和类等。

属性接口
interface InterfaceName {  first: string;  second?: string; //加个问号,接口属性就能够变成可传可不传了,不传默认是undefined。}//打印变量function logParam(name: InterfaceName): void {  console.log(name.first, name.second, 11);}//定义参数const obj = { first: "1", second: "fff", three: 1 };//logParam({ first: "1", second: "1", three: 1 }); //报错,只能传接口定义的值logParam(obj);
tips: 用个变量来存储传入的变量,这样能够传入定义的接口以外的值,否则如果间接传入对象中无接口定义的值会报错,所以倡议接口定义了哪些值就传哪些值。
函数类型接口

对办法传入的参数类型,以及返回值类型进行束缚,可批量进行束缚。

interface keyMap {  (key: string, value: string): string;}let logKeyMap: keyMap = function (key1: string, value: string): string {  return key1 + value;};console.log(logKeyMap("key1", "value"));
tips: 接口只对传入的参数的类型和参数的个数进行束缚,不对参数名称进行束缚。
可索引接口
  • 束缚数组
interface Arr {  [index: number]: string;}let ss: Arr = ["2121"];
  • 束缚对象
interface Obj {  [index: string]: string;}let interfaceArr: Obj = { aa: "1" };

tips:

  1. 数组进行束缚,index后必须跟着number类型。
  2. 对象进行束缚,index后必须跟着string类型
  3. 索引签名参数类型必须为 "string" 或 "number"
类类型接口
  • 进行束缚,相似抽象类的实现。
interface Animals {  name: string;  eat(): void;}class Dogs implements Animals {  name: string;  constructor(name: string) {    this.name = name;  }  eat() {}}
  • 接口继承--接口能够继承接口
interface Dog {  eat(): void;}interface Persons extends Dog {  work(): void;}class Cat {  code() {    console.log("猫在敲代码");  }}//可继承类后再实现接口class SuperMan extends Cat implements Persons {  eat(): void {    console.log(1);  }  work(): void {    console.log(2);  }}let superMan = new SuperMan();superMan.code();
tips: 类接口会对类的属性办法进行束缚,相似非抽象类继承抽象类时必须实现某些办法和属性,但对属性和办法的类型的束缚更加严格,除了办法void类型可被从新定义外,其余属性或办法的类型定义须要和接口保持一致。

泛型

  软件工程中,咱们不仅要创立统一的定义良好的api,同时也要思考可重用性。
组件不仅可能反对以后的数据类型,同时也能反对将来的数据类型,这在创立大型零碎时为你提供了非常灵便的性能

   泛型就是解决接口办法复用性,以及对不特定数据类型的反对。

  要求:传入的参数和返回的参数统一

函数的泛型
function getDate<T>(value: T): T {  return value;}console.log(getDate<number>(123));
tips: 这里的T可改成其余任意值但定义的值,和传入的参数以及返回的参数是一样的,个别默认写法是T,也是业内标准的抉择。
类的泛型
class MinClass<T> {  public list: T[] = [];  //增加  add(value: T): void {    this.list.push(value);  }    //求最小值  min(): T {    //假如这个值最小    let minNum = this.list[0];    for (let i = 0; i < this.list.length; i++) {    //比拟并获取最小值    minNum = minNum < this.list[i] ? minNum : this.list[i];    }    return minNum;  }}//实例化类 并且指定了类的T的类型是numberlet minClass = new MinClass<number>(); minClass.add(23);minClass.add(5);minClass.add(2);console.log(minClass.min()); //实例化类 并且指定了类的T的类型是string,则其办法的传参和返回都是string类型let minClass2 = new MinClass<string>();minClass2.add("23");minClass2.add("5");minClass2.add("2");console.log(minClass2.min());
接口的泛型
  • 第一种写法
interface ConfigFn {  //标准参数类型,返回值类型  <T>(value: T): T;}let getData: ConfigFn = function <T>(value: T): T {  return value;};console.log(getData<string>("z11"));
  • 第二种写法
interface ConfigFn<T> {  //参数类型 ,返回值类型  (value: T): T;}//接口办法function getData<T>(value: T): T {  return value;}//应用接口let myGetDate: ConfigFn<string> = getData;console.log(myGetDate("3"));
tips:接口的泛型只针对函数类型的接口
类当做参数传入泛型类
//用户类--和数据库表字段进行映射class User {  username: string | undefined;  password: string | undefined;  //构造函数-初始化参数  constructor(param: {    username: string | undefined;    password?: string | undefined;  }) {    this.username = param.username;    this.password = param.password;  }}//数据库类class Db<T> {  add(user: T): boolean {    console.log(user);    return true;  }  updated(user: T, id: number): boolean {    console.log(user, id);    return true;  }}let u = new User({  username: "张三",});//u.username = "李四";u.password = "111111";let db = new Db<User>();db.add(u);db.updated(u, 1);
tips: 类的参数名和类型都做了束缚。

模块

  外部模块称为命名空间,内部模块简称为模块,模块在其本身的作用域里执行,而不是在全局作用域里;

  这意味着定义在一个模块里的变量、函数、类等等在模块内部是不可见的,除非你明确的应用export模式之一导出它们。

  相同,如果想应用其它模块导出的变量,函数,类,接口等的时候,你必须要导人它们,能够应用import模式之一。

  咱们能够一些公共的性能独自抽离成一个文件作为一个模块。
模块外面的变量、函数、类等默认是公有的,如果咱们要在内部拜访模块外面的数据(变量、函数、类)
咱们须要通过export裸露模块外面的数据(变量、函数、类...)。
裸露后咱们通过import引入模块就能够应用模块外面裸露的数据(变量、函数、类...)

//modules/db.tsfunction getDate(): any[] {  console.log("获取数据");  return [    {      userName: "张三",    },    {      userName: "李四",    },  ];}//一个模块外面能够用屡次// export { getDate };//一个模块外面只能用一次export default getDate;
 import { getDate as getDbDate } from "./modules/db"; import getDbDate from "./modules/db"; getDbDate();
tips: 这个调试时浏览器中不能间接应用,可在nodeweakpack的环境中调试。

命名空间

  在代码量较大的状况下,为了防止各种变量命名相冲突,可将类似性能的函数、类、接口等搁置到命名空间内
TypeScript的命名空间能够将代码包裹起来,只对外裸露须要在内部拜访的对象。

   命名空间和模块的区别

  • 命名空间:外部模块,次要用于组织代码,防止命名抵触。
  • 模块:ts内部模块的简称,偏重代码的复用,一个模块里可能会有多个命名空间。
 // modules/Animal.tsexport namespace A {  interface Animal {    name: String;    eat(): void;  }  export class Dog implements Animal {    name: String;    constructor(theName: string) {      this.name = theName;    }    eat() {      console.log("我是" + this.name);    }  }}export namespace B {  interface Animal {    name: String;    eat(): void;  }  export class Dog implements Animal {    name: String;    constructor(theName: string) {      this.name = theName;    }    eat() {}  }}
 import { A, B } from "./modules/Animal"; let ee = new A.Dog("小贝"); ee.eat();

装璜器

  • 类装璜器:类装璜器在类申明之前被申明(紧靠着类申明),类装璜器利用于类构造函数,能够用于监督,批改或者替换类定义。
function logClass(params: any) {  console.log(params);  //params 就是指代以后类--HttpClient  params.prototype.apiUrl = "动静扩大属性";  params.prototype.run = function () {    console.log("动静扩大办法");  };  params.prototype.getDate = function () {    console.log("动静扩大办法2");  };}@logClassclass HttpClient {  constructor() {}  getDate() {    console.log(1);  }}let http: any = new HttpClient();console.log(http.apiUrl);http.run();http.getDate();
tips: 装璜器会笼罩被装璜的类中的办法。
  • 装璜器工厂

可传参的装璜器

function logClassB(param: string) {  return function (target: any) {    console.log(target, "装璜器以下的类");    console.log(param, "装璜器传进来的属性");  };}@logClassB("小慧")class HttpClients {  constructor() {}  getDate() {}}let https: any = new HttpClients();console.log(https);
  • 构造函数装璜器
function logClassC(target: any) {  console.log(target, 1111);  //用在这里继承指标类并重载办法和属性  return class extends target {    a: any = "我是批改后的属性";    getDate() {      console.log(this.a + "--装璜器中的办法输入的");    }  };}@logClassCclass HttpClient2 {  public a: string | undefined;  constructor() {    this.a = "我是构造函数外面的a";  }  getDate() {    console.log(this.a);  }}const https2 = new HttpClient2();https2.getDate();
未完待续~

下期预报:在vue中应用ts。