ts基础入门学习总结

typescript

    • 变量的类型注释
    • 数据类型
      • 布尔类型(boolean)
      • 数字类型(number)
      • 字符串类型(string)
      • 数组类型(array)
      • 元组类型(tuple) 属于数组的一种
      • any
      • 枚举类型(enum)
      • null 和 undefined
      • void类型
      • never类型
      • 对象类型(Object)
        • 可选属性
    • 函数
      • 函数的定义
      • 函数可选参数
      • 默认参数
      • 剩余参数
      • ts函数重载
      • ts中类的定义
      • ts中实现继承 extends、 super
      • 类里面的修饰符
      • 静态属性 静态方法
      • typescript中的抽象类
    • 接口
      • 属性接口
      • 接口 :可选属性
      • 函数类型接口
      • 可索引接口:数组、对象的约束 (不常用)
      • 类类型接口
      • 接口扩展:接口可以继承接口
    • 泛型
      • 定义
      • 泛型函数
      • 泛型类
      • 泛型接口
    • 装饰器
      • 定义
      • 类装饰器
        • 类装饰器:普通装饰器(无法传参)
        • 类装饰器:装饰器工厂(可传参)
      • 属性装饰器
      • 方法装饰器
      • 方法参数装饰器
      • 装饰器执行顺序
    • 高级类型
      • 联合类型
        • 定义联合类型

变量的类型注释

const当您使用、var或声明变量时let,您可以选择添加类型注释以显式指定变量的类型:

let myName: string = "Alice";
//变量的类型是根据其初始化程序的类型推断;
let myName = "Alice";

数据类型

布尔类型(boolean)

var flag:boolean=true;
 // flag=123;  //错误
flag=false;  //正确
console.log(flag);

数字类型(number)

 var num:number=123;
 num=456;
 onsole.log(num);  //正确
 num='str';    //错误

字符串类型(string)

var str: string = "this is ts";
str = "haha"; //正确
str = true; //错误

数组类型(array)

有两种方式可以定义数组。 第一种,可以在元素类型后面接上 [],表示由此类型元素组成的一个数组:

let list: number[] = [1, 2, 3];
let list: string[] = ["1", "2","3"];
let arr3:any[]=['131214',22,true];
//这个地方涉及到联合类型
let list: (string | number)[]=[1,1,1,2,"1"]

第二种方式是使用数组泛型,Array<元素类型>:

let list: Array<number> = [1, 2, 3];
let list: Array<string> = ["1", "2","3"];

元组类型(tuple) 属于数组的一种

let arr:[number,string]=[123,'this is ts'];
console.log(arr);

any

有时候,我们会想要为那些在编程阶段还不清楚类型的变量指定一个类型。 这些值可能来自于动态的内容,比如来自用户输入或第三方代码库。 这种情况下,我们不希望类型检查器对这些值进行检查而是直接让它们通过编译阶段的检查。 那么我们可以使用 any类型来标记这些变量:

let notSure: any = 4;
notSure = "maybe a string instead";
notSure = false; 

let list: any[] = [1, true, "free"];
list[1] = 100;

枚举类型(enum)

随着计算机的不断普及,程序不仅只用于数值计算,还更广泛地用于处理非数值的数据。
例如:性别、月份、星期几、颜色、单位名、学历、职业等,都不是数值数据。
在其它程序设计语言中,一般用一个数值来代表某一状态,这种处理方法不直观,易读性差。
如果能在程序中用自然语言中有相应含义的单词来代表某一状态,则程序就很容易阅读和理解。
也就是说,事先考虑到某一变量可能取的值,尽量用自然语言中含义清楚的单词来表示它的每一个值,
这种方法称为枚举方法,用这种方法定义的类型称枚举类型。
enum 枚举名{
标识符[=整型常数],
标识符[=整型常数],

标识符[=整型常数],
} ;

enum Flag {success=1,error=2};
let s:Flag=Flag.success;
console.log(s);//1
enum flag {
  success = "成功",
  error='失败',
}
let s: flag = flag.success;
console.log(s);//成功
enum Color {blue,red,'orange'};
let c:Color=Color.red;
console.log(c);   //1  如果标识符没有赋值 它的值就是下标
// enum Color {blue,red=3,'orange'};
// var c:Color=Color.blue;
// console.log(c);   //0
// var c:Color=Color.red;
// console.log(c);   //3
// var c:Color=Color.orange;
// console.log(c);   //4
enum Err {
  "undefined" = -1,
  "null",
  "success",
}
var e: Err = Err.success;
//负数也是依次递增
console.log(e);//1 

枚举类型提供的一个便利是你可以由枚举的值得到它的名字。 例如,我们知道数值为2,但是不确定它映射到Color里的哪个名字,我们可以查找相应的名字:

enum Color {Red = 1, Green, Blue}
let colorName: string = Color[2];//默认值是从1开始
console.log(colorName);  // 显示'Green'因为上面代码里它的值是2

null 和 undefined

let u: undefined = undefined;
let n: null = null;

let num:number;
console.log(num)  //输出:undefined   报错
//定义没有赋值就是undefined
// let num:number | undefined;
// console.log(num);
 

void类型

typescript中的void表示没有任何类型,一般用于定义方法的时候方法没有返回值。

function warnUser(): void {
    console.log("This is my warning message");
}
//声明一个void类型的变量,可以赋值undefined
let unusable: void = undefined;

never类型

never类型表示的是那些永不存在的值的类型。 例如, never类型是那些总是会抛出异常或根本就不会有返回值的函数表达式或箭头函数表达式的返回值类型; 变量也可能是 never类型,当它们被永不为真的类型保护所约束时。

never类型是任何类型的子类型,也可以赋值给任何类型;然而,没有类型是never的子类型或可以赋值给never类型(除了never本身之外)。 即使 any也不可以赋值给never。

function error(message: string): never {
    throw new Error(message);
}

对象类型(Object)

object表示非原始类型,也就是除number,string,boolean,symbol,null或undefined之外的类型。

function printCoord(pt: { x: number; y: number }) {
  console.log("The coordinate's x value is " + pt.x);
  console.log("The coordinate's y value is " + pt.y);
}
printCoord({ x: 3, y: 7 });
可选属性

对象类型还可以指定它们的部分或全部属性是可选的。为此,请?在属性名称后添加一个

function printName(obj: { first: string; last?: string }) {
  // ...
}
printName({ first: "Bob" });
printName({ first: "Alice", last: "Alisson" });

函数

函数是在 JavaScript 中传递数据的主要方式。TypeScript 允许您指定函数的输入和输出值的类型。

函数的定义

ts定义函数的方法

//函数声明法
function run():string{
    return 'run';
}
//匿名函数
 var fun2=function():number{
   return 123;
}

ts中定义方法传参

 function getInfo(name:string,age:number):string{
                return `${name} --- ${age}`;
        }
alert(getInfo('zhangsan',20));
 var getInfo=function(name:string,age:number):string{
    return `${name} --- ${age}`;
 }
alert(getInfo('zhangsan',40));

没有返回值的方法

 function run():void{
    console.log('run')
 }
 run();

函数可选参数

TypeScript里我们可以在参数名旁使用 ?实现可选参数的功能;

注意:可选参数必须配置到参数的最后面

function getInfo(name: string, age?: number): string {
  if (age) {
    return `${name} --- ${age}`;
  } else {
    return `${name} ---年龄保密`;
  }
}
alert(getInfo("zhangsan"));
alert(getInfo("zhangsan", 123));

默认参数

function getInfo(name: string, age: number = 20): string {
  if (age) {
    return `${name} --- ${age}`;
  } else {
    return `${name} ---年龄保密`;
  }
}
// alert( getInfo('张三'));
alert(getInfo("张三", 30));
//默认参数出现在必须参数前面,用户必须明确的传入 undefined值来获得默认值
function getInfo(age = 20,name: string, ): string {
   if (age) {
     return `${name} --- ${age}`;
   } else {
     return `${name} ---年龄保密`;
   }
 }
 alert( getInfo(undefined,'张三'));

剩余参数

function sum(a:number,b:number,c:number,d:number):number{
    return a+b+c+d;
 }
alert(sum(1,2,3,4)) ;
function sum(...result: number[]): number {
  var sum = 0;
  for (var i = 0; i < result.length; i++) {
    sum += result[i];
  }
  return sum;
}
alert(sum(1, 2, 3, 4, 5, 6));

function sum(a: number, b: number, ...result: number[]): number {
  var sum = a + b;
  for (var i = 0; i < result.length; i++) {
    sum += result[i];
  }
  return sum;
}
alert(sum(1, 2, 3, 4, 5, 6));

ts函数重载

java中方法的重载:重载指的是两个或者两个以上同名函数,但它们的参数不一样,这时会出现函数重载的情况。
typescript中的重载:通过为同一个函数提供多个函数类型定义来试下多种功能的目的。

function getInfo(name:string):string;
function getInfo(age:number):string;
function getInfo(str:any):any{
    if(typeof str==='string'){
        return '我叫:'+str;
    }else{
        return '我的年龄是'+str;
    }
}
// alert(getInfo('张三'));   //正确
// alert(getInfo(20));   //正确
// alert(getInfo(true));    //错误写法
 function getInfo(name: string): string;
 function getInfo(name: string, age: number): string;
 function getInfo(name: any, age?: any): any {
   if (age) {
     return "我叫:" + name + "我的年龄是" + age;
   } else {
     return "我叫:" + name;
   }
 }
// alert(getInfo('zhangsan'));  正确
// alert(getInfo(123));  错误
// alert(getInfo('zhangsan',20));正确

ts中类的定义

class Person {
  name: string; //属性  前面省略了public关键词
  constructor(n: string) {
    //构造函数   实例化类的时候触发的方法
    this.name = n;
  }
  run(): void {
    alert(this.name);
  }
}
var p = new Person("张三");
p.run();

 class Person {
   name: string;
   constructor(name: string) {
     //构造函数   实例化类的时候触发的方法
     this.name = name;
   }
   getName(): string {
     return this.name;
   }
   setName(name: string): void {
     this.name = name;
   }
 }
 var p = new Person("张三");
 alert(p.getName());
 p.setName("李四");
 alert(p.getName());

ts中实现继承 extends、 super

class Person{
    name:string;
    constructor(name:string){
        this.name=name;
    }
    run():string{
        return `${this.name}在运动`
    }
}
class Web extends Person{
    constructor(name:string){
        super(name);  /*初始化父类的构造函数*/
    }
}
// var w=new Web('李四');
// alert(w.run());

类里面的修饰符

typescript里面定义属性的时候给我们提供了 三种修饰符
public : 公有 在当前类里面、 子类 、类外面都可以访问
protected:保护类型 在当前类里面、子类里面可以访问 ,在类外部没法访问 private : 私有 在当前类里面可以访问,子类、类外部都没法访问

属性如果不加修饰符 默认就是 公有 (public)

public :公有 在类里面、 子类 、类外面都可以访问

class Person {
  public name: string; /*公有属性*/

  constructor(name: string) {
    this.name = name;
  }

  run(): string {
    return `${this.name}在运动`;
  }
}
// var p=new Person('王五');
// alert(p.run())
//console.log(p.name);
class Web extends Person {
  constructor(name: string) {
    super(name); /*初始化父类的构造函数*/
  }
  run(): string {
    return `${this.name}在运动-子类`;
  }
  work() {
    alert(`${this.name}在工作`);
  }
}
var w = new Web("李四");
w.work();

protected:保护类型 在类里面、子类里面可以访问 ,在类外部没法访问

class Person {
  protected name: string; /*公有属性*/
  constructor(name: string) {
    this.name = name;
  }
  run(): string {
    return `${this.name}在运动`;
  }
}
var p = new Person("王五");
alert(p.run());
console.log(p.name); //报错 在类外部没法访问
class Web extends Person {
  constructor(name: string) {
    super(name); /*初始化父类的构造函数*/
  }
  work() {
    alert(`${this.name}在工作`);
  }
}
var w = new Web("李四11");
alert(w.work());

private :私有 在类里面可以访问,子类、类外部都没法访问

class Person {
  private name: string; /*私有*/
  constructor(name: string) {
    this.name = name;
  }
  run(): string {
    return `${this.name}在运动`;
  }
}
var p = new Person("王五");
alert(p.run());
console.log(p.name); //报错 在类外部没法访问
class Web extends Person {
  constructor(name: string) {
    super(name);
  }
  work() {
    console.log(`${this.name}在工作`);//报错,子类、类外部都没法访问
  }
}

静态属性 静态方法

静态是指向类自身,而不是指向实例对象;
静态使用:在属性、方法前加上static关键字;
静态属性、方法不会被实例继承。

class Per {
  public name: string;
  public age: number = 20;
  //静态属性
  static sex = "男";
  constructor(name: string) {
    this.name = name;
  }
  run() {
    /*实例方法*/
    alert(`${this.name}在运动`);
  }
  work() {
    alert(`${this.name}在工作`);
  }
  static print() {
    /*静态方法  类里面没法直接调用类里面的属性*/
    console.log(this.name, "123");
    alert("print方法" + Per.sex);
  }
}
var p = new Per("张三");
p.run();
Per.print();
alert(Per.sex);

typescript中的抽象类

它是提供其他类继承的基类,不能直接被实例化。
用abstract关键字定义抽象类和抽象方法,抽象类中的抽象方法不包含具体实现并且必须在派生类中实现。
abstract抽象方法只能放在抽象类里面。
抽象类和抽象方法用来定义标准 。

标准:Animal 这个类要求它的子类必须包含eat方法。

abstract class Animal {
  public name: string;
  constructor(name: string) {
    this.name = name;
  }
  abstract eat(): any; //抽象方法不包含具体实现并且必须在派生类中实现。
  run() {
    console.log("其他方法可以不实现");
  }
}
// var a=new Animal() /*错误的写法*/
class Dog extends Animal {
  //抽象类的子类必须实现抽象类里面的抽象方法
  constructor(name: any) {
    super(name);
  }
  eat() {
    console.log(this.name + "吃粮食");
  }
}
var d = new Dog("小花花");
d.eat();
class Cat extends Animal {
  //抽象类的子类必须实现抽象类里面的抽象方法
  constructor(name: any) {
    super(name);
  }
  run() {}
  eat() {
    console.log(this.name + "吃老鼠");
  }
}
var e=new Cat('小花猫');
e.eat();

接口

接口的作用:在面向对象的编程中,接口是一种规范的定义,它定义了行为和动作的规范,在程序设计里面,接口起到一种限制和规范的作用。接口定义了某一批类所需要遵守的规范,接口不关心这些类的内部状态数据,也不关心这些类里方法的实现细节,它只规定这批类里必须提供某些方法,提供这些方法的类就可以满足实际需要。 typescrip中的接口类似于java,同时还增加了更灵活的接口类型,包括属性、函数、可索引和类等。

属性接口

接口:行为和动作的规范,对批量方法进行约束

interface FullName {
  firstName: string; 
  secondName: string;
}
function printName(name: FullName) {
  // 必须传入对象  firstName  secondName
  console.log(name.firstName + "--" + name.secondName);
}
// printName('1213');  //错误

var obj = {
  /*传入的参数必须包含 firstName  secondName*/ 
  age: 20,
  firstName: "张",
  secondName: "三",
};
printName(obj);

接口 :可选属性

interface FullName{
    firstName:string;
    secondName?:string;
}
function getName(name:FullName){
    console.log(name)
}
getName({
    firstName:'firstName'
})

函数类型接口

对方法传入的参数 以及返回值进行约束 批量约束

interface encrypt{
    (key:string,value:string):string;
}
var md5:encrypt=function(key:string,value:string):string{
        //模拟操作
        return key+value;
}
console.log(md5('name','zhangsan'));
var sha1:encrypt=function(key:string,value:string):string{
    //模拟操作
    return key+'----'+value;
}
console.log(sha1('name','lisi'));

可索引接口:数组、对象的约束 (不常用)

可索引接口 对数组的约束

interface UserArr {
//[index: string]:number;
  [index: number]: string | number;//联合类型
}
var arr:UserArr=['aaa',123];
console.log(arr[0]);

可索引接口 对对象的约束

interface UserObj {
  [index: string]: string;
}
let obj: UserObj = { name: "张三" };

类类型接口

对类的约束 和抽象类抽象有点相似

//定义一个类类型接口
interface Animal{
    name:string;
    eat(str:string):void;
}
//通过implements关键字来实现接口所定义的类,需要具有接口的属性和方法
class Dog implements Animal{
    name:string;
    constructor(name:string){
        this.name=name;
    }
    eat(){
        console.log(this.name+'吃粮食')
    }
}
var d=new Dog('小黑');
d.eat();
class Cat implements Animal {
  name: string;
  constructor(name: string) {
    this.name = name;
  }
  eat(food: string) {
    console.log(this.name + "吃" + food);
  }
}
var c = new Cat("小花");
c.eat("老鼠");

接口扩展:接口可以继承接口

interface Animal {
  eat(): void;
}
//继承Animal接口
interface Person extends Animal {
  work(): void;
}
//定义的类必须包含eat,work方法
class Web implements Person {
  public name: string;
  constructor(name: string) {
    this.name = name;
  }
  eat() {
    console.log(this.name + "喜欢吃馒头");
  }
  work() {
    console.log(this.name + "写代码");
  }
}
var w = new Web("小李");
w.eat();

class Programmer {
  public name: string;
  constructor(name: string) {
    this.name = name;
  }
  coding(code: string) {
    console.log(this.name + code);
  }
}
//继承Programmer,在使用定义的接口Person;
class Web extends Programmer implements Person {
  constructor(name: string) {
    super(name);
  }
  eat() {
    console.log(this.name + "喜欢吃馒头");
  }
  work() {
    console.log(this.name + "写代码");
  }
}
var w = new Web("小李");
// w.eat();
w.coding("写ts代码");
//继承多个
interface Animal1 {
  eat(): void;
}
interface Animal2 {
  run(): void;
}
interface Person extends Animal1, Animal2 {
  work(): void;
}
//定义的类必须包含eat,work方法
class Web implements Person {
  public name: string;
  constructor(name: string) {
    this.name = name;
  }
  eat() {
    console.log(this.name + "喜欢吃馒头");
  }
  work() {
    console.log(this.name + "写代码");
  }
  run(): void {
  }
}
var w = new Web("小李");
w.eat();

泛型

定义

泛型:软件工程中,我们不仅要创建一致的定义良好的API,同时也要考虑可重用性。 组件不仅能够支持当前的数据类型,同时也能支持未来的数据类型,这在创建大型系统时为你提供了十分灵活的功能。

在像C#和Java这样的语言中,可以使用泛型来创建可重用的组件,一个组件可以支持多种类型的数据。 这样用户就可以以自己的数据类型来使用组件。

通俗理解:泛型就是解决 类 接口 方法的复用性、以及对不特定数据类型的支持(类型校验)

泛型函数

泛型:可以支持不特定的数据类型 要求:传入的参数和返回的参数一直

function getData<T>(value: T): T {
  return value;
}
getData<number>(123);
getData<string>("1214231");
getData<number>("2112"); /*错误的写法*/

泛型类

比如有个最小堆算法,需要同时支持返回数字和字符串 a - z两种类型。 通过类的泛型来实现

class MinClas<T>{
    public list:T[]=[];
    add(value:T):void{
        this.list.push(value);
    }
    min():T{        
        var minNum=this.list[0];
        for(var i=0;i<this.list.length;i++){
            if(minNum>this.list[i]){
                minNum=this.list[i];
            }
        }
        return minNum;
    }
}
var m1=new MinClas<number>();   /*实例化类 并且制定了类的T代表的类型是number*/
m1.add(11);
m1.add(3);
m1.add(2);
alert(m1.min())

var m2=new MinClas<string>();   /*实例化类 并且制定了类的T代表的类型是string*/
m2.add('c');
m2.add('a');
m2.add('v');
alert(m2.min())

泛型接口

//函数类型接口
interface ConfigFn {
  (value1: string, value2: string): string;
}
var setData: ConfigFn = function (value1: string, value2: string): string {
  return value1 + value2;
};
setData("name", "张三");
//泛型接口
interface ConfigFn{
    <T>(value:T):T;
}
var getData:ConfigFn=function<T>(value:T):T{
    return value;
}
// getData('张三');
// getData(1243);  //错误

//2、泛型接口
interface ConfigFn<T> {
  (value: T): T;
}
function getData<T>(value: T): T {
  return value;
}
var myGetData: ConfigFn<string> = getData;
myGetData("20"); /*正确*/
// myGetData(20)  //错误

举例
需求:定义一个User的类这个类的作用就是映射数据库字段
然后定义一个 MysqlDb的类这个类用于操作数据库
然后把User类作为参数传入到MysqlDb中

class User {
  username: string | undefined;
  pasword: string | undefined;
}

class MysqlDb {
  add(user: User): boolean {
    console.log(user);
    return true;
  }
}
var u = new User();
u.username = "张三";
u.pasword = "123456";
var Db = new MysqlDb();
Db.add(u);

class ArticleCate {
  title: string | undefined;
  desc: string | undefined;
  status: number | undefined;
}
class MysqlDb {
  add(info: ArticleCate): boolean {
    console.log(info);
    console.log(info.title);
    return true;
  }
}
var a = new ArticleCate();
a.title = "国内";
a.desc = "国内新闻";
a.status = 1;
var Db = new MysqlDb();
Db.add(a);
// 以上问题:代码重复
//定义操作数据库的泛型类
class MysqlDb<T> {
  add(info: T): boolean {
    console.log(info);
    return true;
  }
  updated(info: T, id: number): boolean {
    console.log(info);
    console.log(id);
    return true;
  }
}
//想给User表增加数据
// 1、定义一个User类 和数据库进行映射
// class User{
//     username:string | undefined;
//     pasword:string | undefined;
// }
// var u=new User();
// u.username='张三';
// u.pasword='123456';
// var Db=new MysqlDb();
// Db.add(u);

//2、相关ArticleCate增加数据  定义一个ArticleCate类 和数据库进行映射
class ArticleCate {
  title: string | undefined;
  desc: string | undefined;
  status: number | undefined;
  constructor(params: {
    title: string | undefined;
    desc: string | undefined;
    status?: number | undefined;
  }) {
    this.title = params.title;
    this.desc = params.desc;
    this.status = params.status;
  }
}
//增加操作
let a1 = new ArticleCate({
  title: "分类",
  desc: "1111",
  status: 1,
});

//类当做参数的泛型类
var Db = new MysqlDb<ArticleCate>();
Db.add(a1);
//修改数据
var b2 = new ArticleCate({
  title: "分类111",
  desc: "2222",
});
b2.status = 0;
var Db = new MysqlDb<ArticleCate>();
Db.updated(b2, 12);

功能:定义一个操作数据库的库 支持 Mysql Mssql MongoDb
要求1:Mysql MsSql MongoDb功能一样 都有 add update delete get方法
注意:约束统一的规范、以及代码重用
解决方案:需要约束规范所以要定义接口 ,需要代码重用所以用到泛型
1、接口:在面向对象的编程中,接口是一种规范的定义,它定义了行为和动作的规范
2、泛型 通俗理解:泛型就是解决 类 接口 方法的复用性、

interface DBI<T>{
    add(info:T):boolean;
    update(info:T,id:number):boolean;
    delete(id:number):boolean;
    get(id:number):any[];
}
//定义一个操作mysql数据库的类       注意:要实现泛型接口 这个类也应该是一个泛型类
class MysqlDb<T> implements DBI<T>{
    constructor(){
        console.log('数据库建立连接');
    }
    add(info: T): boolean {
        console.log(info);
        return true;
    }    
    update(info: T, id: number): boolean {
        throw new Error("Method not implemented.");
    }
    delete(id: number): boolean {
        throw new Error("Method not implemented.");
    }
    get(id: number): any[] {
        var list=[
            {
                title:'xxxx',
                desc:'xxxxxxxxxx'
            },
            {
                title:'xxxx',
                desc:'xxxxxxxxxx'
            }
        ]
        return list;
    }
}
//定义一个操作mssql数据库的类  
class MsSqlDb<T> implements DBI<T>{
    constructor(){
        console.log('数据库建立连接');
    }
    add(info: T): boolean {
        console.log(info);
        return true;
    }    
    update(info: T, id: number): boolean {
        throw new Error("Method not implemented.");
    }
    delete(id: number): boolean {
        throw new Error("Method not implemented.");
    }
    get(id: number): any[] {
        var list=[
            {
                title:'xxxx',
                desc:'xxxxxxxxxx'
            },
            {
                title:'xxxx',
                desc:'xxxxxxxxxx'
            }
        ]
        return list;
    }
}
//操作用户表   定义一个User类和数据表做映射
/*
class User{
    username:string | undefined;
    password:string | undefined;
}
var u=new User();
u.username='张三111';
u.password='123456';
var oMysql=new MysqlDb(); //类作为参数来约束数据传入的类型 
oMysql.add(u);
*/
class User{
    username:string | undefined;
    password:string | undefined;
}
var u=new User();
u.username='张三2222';
u.password='123456';

var oMssql=new MsSqlDb<User>();
oMssql.add(u);
//获取User表 ID=4的数据
var data=oMssql.get(4);
console.log(data);

装饰器

定义

装饰器是一种特殊类型的声明,它能够被附加到类声明,方法,属性或参数上,可以修改类的行为。
通俗的讲装饰器就是一个方法,可以注入到类、方法、属性参数上来扩展类、属性、方法、参数的功能。
常见的装饰器有:类装饰器、属性装饰器、方法装饰器、参数装饰器
装饰器的写法:普通装饰器(无法传参) 、 装饰器工厂(可传参)
装饰器是过去几年中js最大的成就之一,已是Es7的标准特性之一

类装饰器

类装饰器在类声明之前被声明(紧靠着类声明)。 类装饰器应用于类构造函数,可以用来监视,修改或替换类定义。 传入一个参数

类装饰器:普通装饰器(无法传参)
function logClass(params: any) {
  console.log(params);
  // params 就是当前类
  params.prototype.apiUrl = "动态扩展的属性";
  params.prototype.run = function () {
    console.log("我是一个run方法");
  };
}
@logClass
class HttpClient {
  constructor() {}
  getData() {}
}
var http: any = new HttpClient();
console.log(http.apiUrl);
http.run();
类装饰器:装饰器工厂(可传参)
function logClass(params: string) {
  return function (target: any) {
    console.log(target);
    console.log(params);
    target.prototype.apiUrl = params;
  };
}
@logClass("http://www.itying.com/api")
class HttpClient {
  constructor() {}
  getData() {}
}
var http: any = new HttpClient();
console.log(http.apiUrl);

下面是一个重载构造函数的例子。
类装饰器表达式会在运行时当作函数被调用,类的构造函数作为其唯一的参数。
如果类装饰器返回一个值,它会使用提供的构造函数来替换类的声明。

function logClass(target: any) {
  console.log(target);
  return class extends target {
    apiUrl: any = "我是修改后的数据";
    getData() {
      this.apiUrl = this.apiUrl + "----";
      console.log(this.apiUrl);
    }
  };
}

@logClass
class HttpClient {
  public apiUrl: string | undefined;
  constructor() {
    this.apiUrl = "我是构造函数里面的apiUrl";
  }
  getData() {
    console.log(this.apiUrl);
  }
}

var http = new HttpClient();
http.getData();

属性装饰器

属性装饰器表达式会在运行时当作函数被调用,传入下列2个参数:
1、对于静态成员来说是类的构造函数,对于实例成员是类的原型对象。
2、成员的名字。

//类装饰器
function logClass(params: string) {
  return function (target: any) {
    console.log(target);
    console.log(params);
  };
}
//属性装饰器
function logProperty(params: any) {
  return function (target: any, attr: any) {
    console.log(target, "logProperty");
    console.log(attr, "logPropertyattr");
    target[attr] = params;
  };
}


@logClass("xxxx")
class HttpClient {
  @logProperty("http://itying.com")
  public url: any | undefined;
  constructor() {}
  getData() {
    console.log(this.url);
  }
}
var http = new HttpClient();
http.getData();

方法装饰器

它会被应用到方法的 属性描述符上,可以用来监视,修改或者替换方法定义。
方法装饰会在运行时传入下列3个参数:
1、对于静态成员来说是类的构造函数,对于实例成员是类的原型对象。
2、成员的名字。
3、成员的属性描述符。

//方法装饰器一
function get(params: any) {
  return function (target: any, methodName: any, desc: any) {
    console.log(target);
    console.log(methodName);
    console.log(desc);
    target.apiUrl = "xxxx";
    target.run = function () {
      console.log("run");
    };
  };
}

class HttpClient {
  public url: any | undefined;
  constructor() {}
  @get("http://www.itying,com")
  getData() {
    console.log(this.url);
  }
}

var http: any = new HttpClient();
console.log(http.apiUrl);
http.run();

//方法装饰器二
function get(params: any) {
  return function (target: any, methodName: any, desc: any) {
    console.log(target);
    console.log(methodName);
    console.log(desc.value);
    //修改装饰器的方法  把装饰器方法里面传入的所有参数改为string类型
    //1、保存当前的方法
    var oMethod = desc.value;
    desc.value = function (...args: any[]) {
      args = args.map((value) => {
        return String(value);
      });
      oMethod.apply(this, args);
    };
  };
}
class HttpClient {
  public url: any | undefined;
  constructor() {}
  @get("http://www.itying,com")
  getData(...args: any[]) {
    console.log(args);
    console.log("我是getData里面的方法");
  }
}
var http = new HttpClient();
http.getData(123, "xxx");

方法参数装饰器

参数装饰器表达式会在运行时当作函数被调用,可以使用参数装饰器为类的原型增加一些元素数据 ,传入下列3个参数:
1、对于静态成员来说是类的构造函数,对于实例成员是类的原型对象。
2、方法的名字。
3、参数在函数参数列表中的索引。

function logParams(params: any) {
  return function (target: any, methodName: any, paramsIndex: any) {
    console.log(params);
    console.log(target);
    console.log(methodName);
    console.log(paramsIndex);
    target.apiUrl = params;
  };
}

class HttpClient {
  public url: any | undefined;
  constructor() {}
  getData(@logParams("xxxxx") uuid: any) {
    console.log(uuid);
  }
}

var http: any = new HttpClient();
http.getData(123456);
console.log(http.apiUrl);

装饰器执行顺序

属性》方法》方法参数》类

如果有多个同样的装饰器,它会先执行后面的

function logClass1(params: string) {
  return function (target: any) {
    console.log("类装饰器1");
  };
}
function logClass2(params: string) {
  return function (target: any) {
    console.log("类装饰器2");
  };
}
function logAttribute1(params?: string) {
  return function (target: any, attrName: any) {
    console.log("属性装饰器1");
  };
}
function logAttribute2(params?: string) {
  return function (target: any, attrName: any) {
    console.log("属性装饰器2");
  };
}
function logMethod1(params?: string) {
  return function (target: any, attrName: any, desc: any) {
    console.log("方法装饰器1");
  };
}
function logMethod2(params?: string) {
  return function (target: any, attrName: any, desc: any) {
    console.log("方法装饰器2");
  };
}
function logParams1(params?: string) {
  return function (target: any, attrName: any, desc: any) {
    console.log("方法参数装饰器1");
  };
}
function logParams2(params?: string) {
  return function (target: any, attrName: any, desc: any) {
    console.log("方法参数装饰器2");
  };
}
@logClass1("http://www.itying.com/api")
@logClass2("xxxx")
class HttpClient {
  @logAttribute1()
  @logAttribute2()
  public apiUrl: string | undefined;
  constructor() {}
  @logMethod1()
  @logMethod2()
  getData() {
    return true;
  }
  setData(@logParams1() attr1: any, @logParams2() attr2: any) {}
}
var http: any = new HttpClient();

高级类型

联合类型

联合类型表示一个值可以是几种类型之一。 我们用竖线( |)分隔每个类型,所以 number | string | boolean表示一个值可以是 number, string,或 boolean。

定义联合类型
function printId(id: number | string) {
  console.log("Your ID is: " + id);
}
// OK
printId(101);
// OK
printId("202");
// Error
printId({ myID: 22342 });

你可能感兴趣的:(typescript)