TypeScript:3月份ts學習筆記整合

各種各樣的類型

基礎類型:  number   string   null   undefined   symbol   boolean   void空

對象類型: {}   Class   function []

const teacher: {
  name: string;
  age: number;
} = {
  name: "Dell",
  age: 18
};
const numbers: number[] = [1, 2, 3];
class Person {}
const my: Person = new Person();
const getNumber: () => number = () => {
  return 123;
};

枚舉類 對應的值默認從0開始 可以手動賦值

enum Status {
  OFFLINE,
  ONLINE,
  DELETED
}
console.log(Status.OFFLINE);
console.log(Status[0]);
function getResult(status) {
  if (status === Status.OFFLINE) {
    return "offline";
  } else if (status === Status.ONLINE) {
    return "online";
  } else if (status === Status.DELETED) {
    return "deleted";
  } else {
    return "error";
  }
}
let result = getResult(Status.OFFLINE);
console.log(result);

never: 永遠不會執行完函數

function errorEmitter(): never {
  throw new Error();
}
function whileEmitter(): never {
  while (true) {}
}

數組:

const numberArr: number[] = [1, 2, 3];
const arr: (number | string)[] = [1, "2", "3"];
const objectArr: { name: string }[] = [{ name: "1" }, { name: "2" }];

元組:

const teacherInfo: [string, string, number] = ["yh", "nv", 10];
const teacherList: [string, number][] = [
  ["yh", 10],
  ["hy", 20]
];

type  alias 類型別名:

type User = { name: string; age: number };
const objArr: User[] = [
  { name: "1", age: 10 },
  { name: "2", age: 11 }
];
class Teacher {
  name: string;
  age: number;
}
const objArr1: Teacher[] = [
  new Teacher(),
  {
    name: "h",
    age: 10
  }
];

type  annotation 類型註解 我們來告訴ts變量類型

type  inference 類型推斷 ts自動嘗試分析變量類型


接口、類、繼承

接口:

interface Person {
  //readonly name: string; //修飾符只讀不能賦值
  name: string;
  age?: number; //加一個?表示可有可無
  [propName: string]: any; //可以傳 名字爲字符串 值爲任何類型
  //say(): string;
}
const getName = (person: Person) => {
  console.log(person.name);
};
getName({ name: "yh" });
class Users implements Person {
  //在類裏用接口
  name = "yh";
  // say() {
  //   return "hello";
  // }
}
interface Study extends Person {
  //接口繼承
  // hight: string;
}

類繼承:

class Persons {
  name: string = "yh";
  getName() {
    return this.name;
  }
}
//類繼承 Teachers是子類  Persons是父類
class Teachers extends Persons {
  getTeacherName() {
    return "teacher";
  }
  getName() {
    //super.getName(); 調用父類方法
    return super.getName() + "覆蓋父類getName方法";
  }
}
const person = new Persons();
console.log(person.getName()); //直接運行ts代碼 ts-node type2.ts
const teacher = new Teachers();
console.log(teacher.getName());

訪問類型: private允許在類內調用 protected允許在類內及繼承的子類中使用 public允許在類的內外調用

 public name: string;
  //private name: string;
  //protected name:string;
  sayHi() {
    console.log("111");
  }
}

類構造器: constructor

class Person3 {
  // public name: string;
  // constructor(name: string) {
  //   this.name = name;
  // }
  constructor(public name: string) {}
}
const person3 = new Person3("yh");
console.log(person3.name);
class Teacher3 extends Person3 {
  constructor(age: number) {
    super("yh"); //子類用構造器需調用父類構造器
  }
}
const teacher3 = new Teacher3(28);

get  set:

class Person4 {
  constructor(private _name: string) {}
  get name() {
    return this._name;
  }
  set name(name: string) {
    this._name = name;
  }
}
const person4 = new Person4("yh");
console.log(person4.name);
person4.name = "yh"; //賦值

構建一個單例:

class Demo {
  private static instance: Demo;
  private constructor() {}
  static getInstance() {
    if (!this.instance) {
      this.instance = new Demo();
    }
    return this.instance;
  }
}
const demo1 = Demo.getInstance();

抽象類: 抽象方法 把公用的東西抽象出來

abstract class Geom {
  width: number;
  getType() {
    return "Geom";
  }
  abstract getArea(): number;
}
class Circle extends Geom {
  getArea() {
    return 123;
  }
}
class Square extends Geom {
  getArea() {
    return 456;
  }
}

抽象接口:

interface Person6 {
  name: string;
}
interface teacher6 extends Person6 {}
interface stydent extends Person6 {
  age: number;
}
const teacher6 = {
  name: "yh"
};
const stydent = {
  name: "hy",
  age: 18
};
const getUserInfo = (user: Person6) => {
  console.log(user.name);
};
getUserInfo(stydent);

聯合類型+類型保護

聯合類型:

interface Bird {
  fly: boolean;
  sing: () => {};
}
interface Dog {
  fly: boolean;
  bark: () => {};
}

類型保護:

//類型斷言方式 as語法
function canDo(animal: Bird | Dog) {
  if (animal.fly) {
    (animal as Bird).sing();
  } else {
    (animal as Dog).bark();
  }
}
//in 語法
function cantDo(animal: Bird | Dog) {
  if ("sing" in animal) {
    animal.sing();
  } else {
    animal.bark();
  }
}
//typeof 語法
function add(first: string | number, second: string | number) {
  if (typeof first === "string" || typeof second === "string") {
    return `${first}${second}`;
  }
  return first + second;
}
//instanceof 語法  不能用interface
class NumberObj {
  count: number;
}
function addSecond(first: object | NumberObj, second: object | NumberObj) {
  if (first instanceof NumberObj && second instanceof NumberObj) {
    return first.count + second.count;
  } else {
    return 0;
  }
}

泛型

泛型是指—–generic 泛指的類型 調用時指定類型

function join<T>(first: T, second: T): T {
  return first;
}
join<string>("1", "123");

數組泛型 T[]

function map<T>(params: Array<T>) {
  return params;
}
map<string>(["123"]);

多個泛型

function add<T, P>(first: T, second: P) {
  return `${first}+${second}`;
}
add<number, string>(1, "11");

類中泛型

class DataManager<T> {
  constructor(private data: T[]) {}
  getItem(index: number): T {
      return this.data[index];
  }
}
const data = new DataManager<number>([1, 2]);
data.getItem(0);

泛型繼承

interface Item {
  name: string;
}
class DataManager1<T extends Item> {
  constructor(private data: T[]) {}
  getItem(index: number): string {
    return this.data[index].name;
  }
}
const data1 = new DataManager1([{ name: "dd" }]);

使用泛型作爲一個具體的類型註解

const funcs: <T>() => string = <T>() => {
  return "123";
};

function hello<T>(param: T) {
  return param;
}
const func: <T>(param: T) => T = hello;

泛型中使用keyof語法

interface Person {
  name: string;
  age: number;
}
class Teacher {
  constructor(private info: Person) {}
  //循環Person -> T的類型爲string ->返回類型爲T的類型
  getInfo<T extends keyof Person>(key: T): Person[T] {
    return this.info[key];
  }
}
const teacher = new Teacher({
  name: "dell",
  age: 18
});
const test = teacher.getInfo("name");
console.log(test);

namespace命名空間

在ts中初步的模塊化思想就是namespace(命名空間)

//編譯後只生成一個變量
namespace Home {
  class Header {
    constructor() {
      const elem = document.createElement("div");
      elem.innerText = "Header";
      document.body.appendChild(elem);
    }
  }
  class Content {
    constructor() {
      const elem = document.createElement("div");
      elem.innerText = "Content";
      document.body.appendChild(elem);
    }
  }
  //只暴露這一個類
  export class Page {
    constructor() {
      new Header();
      new Content();
    }
  }
  //定義接口
  export interface Uset{
    name:string
  }
  //定義子空間
  export namespace childHome Uset{
    export class Test{}
  }
}

兩個ts文件中命名空間相互引用時,會使用依賴聲明來標註

聲明方式:///<reference path=’./components.ts’/>


.d.ts註解文件

ts裏有一種獨特的文件,以.d.ts結尾,這種文件叫做類型描述文件。註解文件通常使用declare關鍵字描述類型

這裏以jquery爲例,現在想在ts文件種使用jq的方法,如下:

//import $ from "jquery"; //es6引入jq模塊包 這裏的引用名字和註解文件裏的名字要相同
$(function() {
  $("body").html("123");
  new $.fn.init();
});

這時需要創建一個jquery.d.ts文件幫助ts理解jq,分爲兩種情況,外部引入jq和Es6引入jq模塊包

第一種   (外部引入jq.js文件)

函數重載:聲明 -> $的類型是函數,接收函數,返回值是空

interface JqueryInstance {
  html: (html: string) => {};
}
declare function $(readyFunc: () => void): void;
declare function $(selector: string): JqueryInstance;
//對類和對象進行類型定義,命名空間嵌套
declare namespace $ {
  namespace fn {
    class init {}
  }
}

interface的方式實現函數重載

interface JQuery {
  (readyFunc: () => void): void;
  (selector: string): JqueryInstance;
}
declare var $: JQuery;

第二種(Es6引入jq模塊包)

Es6模塊化必須要添加註解  module後的名字和引用的名字一樣

declare module "jquery" {
  interface JqueryInstance {
    html: (html: string) => {};
  }
  //混合類型
  function $(readyFunc: () => void): void;
  function $(selector: string): JqueryInstance;
  namespace $ {
    namespace fn {
      class init {}
    }
  }
  export = $;
}

奇奇怪怪的裝飾器

學習準備裝飾器是實驗性特性,未來可能會不是這種用法

現在想要使用需要在tsconfig.json文件中打開這兩個註釋,否則使用裝飾器會報錯

裝飾器本身是一個函數 通過@符號使用

類的裝飾器

接收的參數是類的構造函數    創建類後立即執行

多個裝飾器執行時  從下到上執行

function testDecorator(constructor: any) {
  //在類上創建getName方法
  constructor.prototype.getName = () => {
    console.log("dell");
  };
}
function testDecorator1(constructor: any) {
  console.log("先執行");
}
//多個裝飾器執行時 從下到上執行
@testDecorator
@testDecorator1
class Test {}
const test = new Test();
(test as any).getName();
//對裝飾器進行 工廠函數包裝
function testDecorator2(flag: boolean) {
  if (flag) {
    return function(constructor: any) {
      constructor.prototype.getName = () => {
        console.log("dell");
      };
    };
  } else {
    return function(constructor: any) {};
  }
}
@testDecorator2(true)
class Test2 {}
const test2 = new Test2();
//(test2 as any).getName();
//new (...args: any[])=> {} 這是一個構造函數 接收很多都是any類型的參數 返回很多any類型的值
function testDecorator3<T extends new (...args: any[]) => {}>(constructor: T) {
  //對類裏的構造函數做擴展 會先執行原來的構造函數
  return class extends constructor {
    name = "lee";
    getName() {
      return this.name;
    }
  };
}
@testDecorator3
class Test3 {
  name: string;
  constructor(name: string) {
    this.name = name;
  }
}
const test3 = new Test3("dell");
//工廠模式 ->識別裝飾器中新增的類方法
function testDecorator4() {
  return function<T extends new (...args: any[]) => {}>(constructor: T) {
    //對類裏的構造函數做擴展 會先執行原來的構造函數
    return class extends constructor {
      name = "lee";
      getName() {
        return this.name;
      }
    };
  };
}
const Test4 = testDecorator4()(
  class {
    name: string;
    constructor(name: string) {
      this.name = name;
    }
  }
);
const test4 = new Test4("dell");
test4.getName();

方法裝飾器

普通方法接收的參數:target對應類的prototype原型,key對應裝飾函數的名字,descriptor設置方法的屬性

靜態方法接收的參數:target對應類的構造函數

function getNameDecorator(
  target: any,
  key: string,
  descriptor: PropertyDescriptor
) {
  //此函數是否可以在外部再次修改
  descriptor.writable = false;
  //對方法的內容做變更
  descriptor.value = function() {
    return "Decorator";
  };
}
class Func {
  name: string;
  constructor(name: string) {
    this.name = name;
  }
  //普通方法
  @getNameDecorator
  getName() {
    return this.name;
  }
  //靜態方法
  // @getNameDecorator
  // static getName1() {
  //   return 123;
  // }
}
const func = new Func("dell");
console.log(func.getName());

訪問器裝飾器

function visitDecorator(
  target: any,
  key: string,
  descriptor: PropertyDescriptor
) {}
class Visit {
  private _name: string;
  constructor(name: string) {
    this._name = name;
  }
  get name() {
    return this._name;
  }
  @visitDecorator
  set name(name: string) {
    this._name = name;
  }
}
const visit = new Visit("dell");
visit.name = "1233333";
console.log(visit.name);

屬性裝飾器

function nameDecorator(target: any, key: string): any {
  //target[key] = 'lee';  //這裏修改的使原型上的屬性,不是實例上的 獲取方法->(names as any).__proto__.name
  //創建一個替換name的descriptor,使name不能在外部被修改
  const descriptor: PropertyDescriptor = {
    writable: false
  };
  return descriptor;
}
class Name {
  @nameDecorator
  name = "Dell";
}
const names = new Name();
console.log(names.name);

參數裝飾器

三個參數 target原型 method方法名 paramIndex參數的位置

function paramDecorator(target: any, method: string, paramIndex: number) {}
class Param {
  getInfo(name: string, @paramDecorator age: number) {
    console.log(name, age);
  }
}
const param = new Param();
param.getInfo("dell", 18);

一個裝飾器的小例子

使用裝飾器統一判斷uesrInfo是否是 undefined

const uesrInfo: any = undefined;
function catchErroe(msg: string) {
  return function(target: any, key: string, descriptor: PropertyDescriptor) {
    const fn = descriptor.value;
    descriptor.value = function() {
      try {
        fn();
      } catch (e) {
        console.log(`${msg}有問題`);
      }
    };
  };
}
class GetInfo {
  @catchErroe("name")
  getNAme() {
    return uesrInfo.name;
  }
  @catchErroe("age")
  getAge() {
    return uesrInfo.age;
  }
}
const getInfo = new GetInfo();

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章