Typescript 入门

 一、Typescript 介绍
1. TypeScript 是由微软开发的一款开源的编程语言。
2、TypeScript 是 Javascript 的超级,遵循最新的 ES6、Es5 规范。TypeScript 扩展了 JavaScript
的语法。
3. TypeScript 更像后端 java、C#这样的面向对象语言可以让 js 开发大型企业项目。
4、谷歌也在大力支持 Typescript 的推广,谷歌的 angular2.x+就是基于 Typescript 语法。
5、最新的 Vue 、React 也可以集成 TypeScript。

 二、Typescript 装 安装 编译
npm install -g typescript
tsc helloworld.ts

三、Typescript 具 开发工具 Vscode 自动编译.ts 文件
1. 创建 tsconfig.json 文件 tsc --init 生成配置文件


2、点击菜单 任务-运行任务 点击 tsc:监视-tsconfig.json 然后就可以自动生成代码了

 四、Typescript 具 开发工具 HBuilder  自动编译.ts 文件
1.在最上方菜单栏,点击工具-插件安装;
2.点击下方浏览 Eclipse插件市场,搜索 typescript 插件进行安装
3.安装完成后重启编译器,点击菜单栏工具-选项 选择编译 ts 文件
4.在你的项目上右键点击--配置--Enable TypeScript Builder,之后你再保存.ts 文件
时会自动在当前目录编译出对应的.js 文件
在Compile all TypeScript files on build 进行打勾,然后确定;

typeScript中的数据类型
    typescript中为了使编写的代码更规范,更有利于维护,增加了类型校验,在typescript中主要给我们提供了以下数据类型
        布尔类型(boolean)
        数字类型(number)
        字符串类型(string)
        数组类型(array)
        元组类型(tuple)
        枚举类型(enum)
        任意类型(any)
        null 和 undefined
        void类型
        never类型

布尔类型(boolean)
    var flag:boolean=true;
    // flag=123;  //错误
    flag=false;  //正确
 数字类型(number)
    var num:number=123;
    num=456;
    num='str';    //错误
数组类型(array)  ts中定义数组有两种方式
    1.第一种定义数组的方式
     var arr:number[]=[11,22,33];
    2.第二种定义数组的方式
    var arr:Array<number>=[11,22,33];
元组类型(tuple)  属于数组的一种
     var arr:Array<number>=[11,22,33];
     let arr:[number,string]=[123,'this is ts'];

枚举类型(enum)
    随着计算机的不断普及,程序不仅只用于数值计算,还更广泛地用于处理非数值的数据。
    例如:性别、月份、星期几、颜色、单位名、学历、职业等,都不是数值数据。  
    在其它程序设计语言中,一般用一个数值来代表某一状态,这种处理方法不直观,易读性差。
    如果能在程序中用自然语言中有相应含义的单词来代表某一状态,则程序就很容易阅读和理解。
    也就是说,事先考虑到某一变量可能取的值,尽量用自然语言中含义清楚的单词来表示它的每一个值,
    这种方法称为枚举方法,用这种方法定义的类型称枚举类型。
    enum 枚举名{ 
        标识符[=整型常数], 
        标识符[=整型常数], 
         ... 
        标识符[=整型常数], 
     } ;      
enum Flag {success=1,error=2};
let s:Flag=Flag.success;
console.log(s);   // 1
enum Flag {success=1,error=2};
let f:Flag=Flag.error;
console.log(f);    // 2      
enum Color {blue,red,'orange'};
var c:Color=Color.red;
console.log(c);   //1  如果标识符没有赋值 它的值就是下标
enum Color {blue,red=3,'orange'};
var c:Color=Color.red;
console.log(c);   //3
var c:Color=Color.orange;
console.log(c);   //4
enum Err {'undefined'=-1,'null'=-2,'success'=1};
var e:Err=Err.success;
console.log(e);   // 1

任意类型(any)
//任意类型的用处
var oBox:any=document.getElementById('box');
oBox.style.color='red';

 null 和 undefined  其他(never类型)数据类型的子类型
var num:number;
 console.log(num)  //输出:undefined   报错
var num:undefined;
console.log(num)  //输出:undefined  //正确
var num:number | undefined;
 num=123;    console.log(num);   //123
定义没有赋值就是undefined
var num:number | undefined;
console.log(num);   //undefined
一个元素可能是 number类型 可能是null 可能是undefined
var num:number | null | undefined;

 void类型 :typescript中的void表示没有任何类型,一般用于定义方法的时候方法没有返回值。
//表示方法没有返回任何类型
function run():void{
    console.log('run')
}
run();
function run():number{
    return 123;
}
run();

 never类型:是其他类型 (包括 null 和 undefined)的子类型,代表从不会出现的值。这意味着声明never的变量只能被never类型所赋值。
var a:never;
    a=123; //错误的写法
    a=(()=>{
        throw new Error('错误');
    })()

typeScript中的函数
3.1、函数的定义
es5定义函数的方法
    //函数声明法
function run(){
    return 'run';
}
    //匿名函数
var run2=function(){
    return 'run2';
}
ts中定义函数的方法
 //函数声明法
function run():string{
    return 'run';
}
  //错误写法
function run():string{
    return 123;
}
//匿名函数
var fun2=function():number{
    return 123;
}
console.log(fun2()); /*调用方法*/
//ts中定义方法传参
function getInfo(name:string,age:number):string{
    return `${name} --- ${age}`;
}
console.log(getInfo('zhangsan',20));
var getInfo=function(name:string,age:number):string{
    return `${name} --- ${age}`;
}
console.log(getInfo('zhangsan',18));
//没有返回值的方法
function run():void{
    console.log('run')
}
run();
3.2、方法可选参数 
es5里面方法的实参和行参可以不一样,但是ts中必须一样,如果不一样就需要配置可选参数 
function getInfo(name:string,age?:number):string{
    if(age){
        return `${name} --- ${age}`;
    }else{
        return `${name} ---年龄保密`;
    }
}
console.log(getInfo('zhangsan'))
console.log(getInfo('zhangsan',123))
     注意:可选参数必须配置到参数的最后面
    //错误写法
function getInfo(name?:string,age:number):string{
    if(age){
        return `${name} --- ${age}`;
    }else{
        return `${name} ---年龄保密`;
    }
}
console.log(getInfo('zhangsan'))
3.3、默认参数 可选参数
es5里面没法设置默认参数,es6和ts中都可以设置默认参数
function getInfo(name:string,age:number=20):string{
    if(age){
        return `${name} --- ${age}`;
    }else{
        return `${name} ---年龄保密`;
    }
}
console.log( getInfo('张三'));
console.log( getInfo('张三',18));
3.4、剩余参数
function sum(a:number,b:number,c:number,d:number):number{
    return a+b+c+d;
}
console.log(sum(1,2,3,4)) ;  //10
    //三点运算符 接受新参传过来的值
function sum(...result:number[]):number{
    var sum=0;
    for(var i=0;i<result.length;i++){
        sum+=result[i];  
    }
    return sum;
}
console.log(sum(1,2,3,4,5,6)) ;  //21
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;
}
console.log(sum(1,2,3,4,5,6)) ;  //21
3.5、ts函数重载
     java中方法的重载:重载指的是两个或者两个以上同名函数,但它们的参数不一样,这时会出现函数重载的情况。
    typescript中的重载:通过为同一个函数提供多个函数类型定义来试下多种功能的目的。
    ts为了兼容es5 以及 es6 重载的写法和java中有区别。
es5中出现同名方法,下面的会替换上面的方法 
function css(config){
}
function css(config,value){
}
    ts中的重载
function getInfo(name:string):string;
function getInfo(age:number):string;
function getInfo(str:any):any{
    if(typeof str==='string'){
        return '我叫:'+str;
    }else{
        return '我的年龄是'+str;
    }
}
console.log(getInfo('张三'));   //正确
console.log(getInfo(20));   //正确
console.log(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;
    }
}
console.log(getInfo('zhangsan'));  /*正确*/
console.log(getInfo(123));      // 错误
console.log(getInfo('zhangsan',20));
.6、箭头函数  es6  
this指向的问题    箭头函数里面的this指向上下文
setTimeout(function(){
    console.log('run')
},1000)
setTimeout(()=>{
    console.log('run')
},1000)

es5里面的类  
1.最简单的类
function Person(){
    this.name='张三';
    this.age=20;
}
var p=new Person();
console.log(p.name);
2、构造函数和原型链里面增加方法
function Person(){
    this.name='张三';  /*属性*/
    this.age=20;
    this.run=function(){
        console.log(this.name+'在运动');
    }
}
//原型链上面的属性会被多个实例共享   构造函数不会
Person.prototype.sex="男";
Person.prototype.work=function(){
    console.log(this.name+'在工作');
}
var p=new Person();
p.run();
p.work();   //张三在工作

3.类里面的静态方法
function Person(){
    this.name='张三';  /*属性*/
    this.age=20;
    this.run=function(){  /*实例方法*/
        console.log(this.name+'在运动');
    }
}
Person.getInfo=function(){
    console.log('我是静态方法');
}
 //原型链上面的属性会被多个实例共享   构造函数不会
 Person.prototype.sex="男";
 Person.prototype.work=function(){
     console.log(this.name+'在工作');
}
var p=new Person();    
p.work();
//调用静态方法
Person.getInfo();

4、es5里面的继承   对象冒充实现继承
function Person(){
    this.name='张三';  /*属性*/
    this.age=20;
    this.run=function(){  /*实例方法*/
        console.log(this.name+'在运动');
     }
}      
Person.prototype.sex="男";
Person.prototype.work=function(){
    console.log(this.name+'在工作');
}
//Web类 继承Person类   原型链+对象冒充的组合继承模式
function Web(){
    Person.call(this);    /*对象冒充实现继承*/
}
var w=new Web();
w.run();  //对象冒充可以继承构造函数里面的属性和方法
w.work();  //报错 //对象冒充可以继承构造函数里面的属性和方法, 但是没法继承原型链上面的属性和方法

5、es5里面的继承   原型链实现继承
function Person(){
    this.name='张三';  /*属性*/
    this.age=20;
    this.run=function(){  /*实例方法*/
        console.log(this.name+'在运动');
    }
}      
Person.prototype.sex="男";
Person.prototype.work=function(){
    console.log(this.name+'在工作');
}
//Web类 继承Person类   原型链+对象冒充的组合继承模式
function Web(){
}
Web.prototype=new Person();   //原型链实现继承
var w=new Web();
//原型链实现继承:可以继承构造函数里面的属性和方法 也可以继承原型链上面的属性和方法
w.run();
w.work();

6、 原型链实现继承的 问题?
function Person(name,age){
    this.name=name;  /*属性*/
    this.age=age;
    this.run=function(){  /*实例方法*/
        console.logt(this.name+'在运动');
    }
}      
Person.prototype.sex="男";
Person.prototype.work=function(){
    console.log(this.name+'在工作');
}
var p=new Person('李四',20);
p.run();

function Person(name,age){
    this.name=name;  /*属性*/
    this.age=age;
    this.run=function(){  /*实例方法*/
        console.log(this.name+'在运动');
    }
}      
Person.prototype.sex="男";
Person.prototype.work=function(){
    console.log(this.name+'在工作');
}
function Web(name,age){
}
Web.prototype=new Person();
var w=new Web('赵四',20);   //实例化子类的时候没法给父类传参
w.run();  //undefined 在运动
var w1=new Web('王五',22);

7.原型链+对象冒充的组合继承模式
function Person(name,age){
    this.name=name;  /*属性*/
    this.age=age;
    this.run=function(){  /*实例方法*/
        console.log(this.name+'在运动');
    }
}      
Person.prototype.sex="男";
 Person.prototype.work=function(){
        console.log(this.name+'在工作');
}
function Web(name,age){
        Person.call(this,name,age);   //对象冒充继承   实例化子类可以给父类传参
}
 Web.prototype=new Person();
var w=new Web('赵四',20);   //实例化子类的时候没法给父类传参
w.run();
w.work();
var w1=new Web('王五',22);

8、原型链+对象冒充继承的另一种方式
function Person(name,age){
    this.name=name;  /*属性*/
    this.age=age;
    this.run=function(){  /*实例方法*/
        console.log(this.name+'在运动');
    }
}      
Person.prototype.sex="男";
Person.prototype.work=function(){
    console.log(this.name+'在工作');
}
function Web(name,age){
    Person.call(this,name,age);   //对象冒充继承  可以继承构造函数里面的属性和方法、实例化子类可以给父类传参
}
Web.prototype=Person.prototype;
var w=new Web('赵四',20);   //实例化子类的时候没法给父类传参
w.run();
w.work();
var w1=new Web('王五',22);

1、ts中类的定义
class Person{
    name:string;   //属性  前面省略了public关键词
    constructor(n:string){  //构造函数   实例化类的时候触发的方法
        this.name=n;
    }
    run():void{
    console.log(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('张三');
console.log(p.getName());   //张三
p.setName('李四');
console.log(p.getName());  //李四

2、ts中实现继承  extends、 super
class Person{
    name:string;
    constructor(name:string){
        this.name=name;
    }
    run():string{
        return `${this.name}在运动`
    }
}
var p=new Person('王五');
console.log(p.run())
class Web extends Person{
    constructor(name:string){
        super(name);  /*初始化父类的构造函数*/
    }
}
var w=new Web('李四');
console.log(w.run());   //李四在运动
    //ts中继承的探讨  父类的方法和子类的方法一致
class Person{
     name:string;
    constructor(name:string){
        this.name=name;
    }
    run():string{
         return `${this.name}在运动`
    }
}
var p=new Person('王五');
console.log(p.run())
class Web extends Person{
    constructor(name:string){
         super(name);  /*初始化父类的构造函数*/
    }
     run():string{
        return `${this.name}在运动-子类`
    }
    work(){
        console.log(`${this.name}在工作`)
    }
}
var w=new Web('李四');
console.log(w.run());
 w.work();
console.log(w.run());   //子类

3 类里面的修饰符  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('王五');
console.log(p.run())
class Web extends Person{
    constructor(name:string){
         super(name);  /*初始化父类的构造函数*/
    }
    run():string{
        return `${this.name}在运动-子类`
    }
    work(){
        console.log(`${this.name}在工作`)
    }
}
var w=new Web('李四');
w.work();
//类外部访问公有属性
class Person{
    public name:string;  /*公有属性*/
    constructor(name:string){
        this.name=name;
    }
    run():string{
        return `${this.name}在运动`
    }
}
var  p=new Person('哈哈哈');
console.log(p.name);

//protected:保护类型    在类里面、子类里面可以访问 ,在类外部没法访问
class Person{
    protected name:string;  /*公有属性*/
    constructor(name:string){
        this.name=name;
    }
    run():string{
        return `${this.name}在运动`
    }
}
var p=new Person('王五');
console.log(p.run())
class Web extends Person{
    constructor(name:string){
        super(name);  /*初始化父类的构造函数*/
    }                  
    work(){
        console.logt(`${this.name}在工作`)
    }
}
var w=new Web('李四11');
w.work(); 
console.log( w.run());   //李四11在运动
//类外外部没法访问保护类型的属性
class Person{
    protected name:string;  /*保护类型*/
    constructor(name:string){
        this.name=name;
    }
    run():string{
        return `${this.name}在运动`
    }
}
var  p=new Person('哈哈哈');
console.log(p.name);  //错误
// private :私有        在类里面可以访问,子类、类外部都没法访问
class Person{
    private name:string;  /*私有*/
    constructor(name:string){
        this.name=name;
    }
    run():string{
         return `${this.name}在运动`
    }
}
class Web extends Person{
    constructor(name:string){
        super(name)
    }
    work(){
        console.log(`${this.name}在工作`)  //报错
    }
}
class Person{
    private name:string;  /*私有*/
    constructor(name:string){
        this.name=name;
    }
     run():string{
         return `${this.name}在运动`
    }
}
var p=new Person('哈哈哈');
console.log(p.run());

// 静态属性 静态方法  
function Person(){
    this.run1=function(){  实例方法
    }
}
Person.name='哈哈哈';    静态属性
Person.run2=function(){  静态方法
    }
var p=new Person();
Person.run2(); 静态方法的调用

function $(element){
    return new Base(element)
}
$.get=function(){
}
function Base(element){
    this.element=获取dom节点;
    this.css=function(arr,value){
        this.element.style.arr=value;
    }
}
$('#box').css('color','red')
$.get('url',function(){
})

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

//多态:父类定义一个方法不去实现,让继承它的子类去实现  每一个子类有不同的表现 
//多态属于继承
class Animal {
    name:string;
    constructor(name:string) {
        this.name=name;
    }
    eat(){   //具体吃什么  不知道 ,具体吃什么?继承它的子类去实现 ,每一个子类的表现不一样
        console.log('吃的方法')
    }
}
class Dog extends Animal{
    constructor(name:string){
        super(name)
    }
    eat(){
         return this.name+'吃粮食'
    }
}
class Cat extends Animal{
    constructor(name:string){
        super(name)
    }
    eat(){
        return this.name+'吃老鼠'
    }
}

//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 c=new Cat('小花猫');
c.eat();

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

定义标准。

1、属性接口     对json的约束
//ts中定义方法
function printLabel():void {
    console.log('printLabel');
}
printLabel();

ts中定义方法传入参数
function printLabel(label:string):void {
    console.log('printLabel');
}
printLabel('haha');
ts中自定义方法传入参数,对json进行约束
function printLabel(labelInfo:{label:string}):void {
console.log('printLabel');
}
printLabel('haha'); //错误写法
 printLabel({name:'张三'});  //错误的写法
printLabel({label:'张三'});  //正确的写法

//对批量方法传入参数进行约束。
//接口:行为和动作的规范,对批量方法进行约束
//就是传入对象的约束    属性接口
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 printName(name:FullName){
    // 必须传入对象  firstName  secondName
    console.log(name.firstName+'--'+name.secondName);
}
function printInfo(info:FullName){
    // 必须传入对象  firstName  secondName
    console.log(info.firstName+info.secondName);
}
var obj={   /*传入的参数必须包含 firstName  secondName*/
    age:20,
    firstName:'张',
    secondName:'三'
};
printName(obj);
printInfo({
    firstName:'李',
    secondName:'四'
})

//接口 :可选属性
interface FullName{
    firstName:string;
    secondName:string;
}
function getName(name:FullName){
    console.log(name)
}
//参数的顺序可以不一样
getName({        
    secondName:'secondName',
     firstName:'firstName'
})

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

$.ajax({
type: "GET",
 url: "test.json",
data: {username:$("#username").val(), content:$("#content").val()},
dataType: "json"             
});
         
interface Config{
    type:string;
    url:string;
    data?:string;
    dataType:string;
}
//原生js封装的ajax 
function ajax(config:Config){
    var xhr=new XMLHttpRequest();
    xhr.open(config.type,config.url,true);
    xhr.send(config.data);
    xhr.onreadystatechange=function(){
        if(xhr.readyState==4 && xhr.status==200){
            console.log('success');
            if(config.dataType=='json'){
                console.log(JSON.parse(xhr.responseText));
            }else{
                console.log(xhr.responseText)
            }
        }
    }
}
ajax({
    type:'get',
    data:'name=zhangsan',
    url:'http://a.itying.com/api/productlist', //api
    dataType:'json'
})

 函数类型接口:对方法传入的参数 以及返回值进行约束    批量约束

// 加密的函数类型接口
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'));

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

//ts定义数组的方式
var arr:number[]=[2342,235325]
var arr1:Array<string>=['111','222']
//可索引接口 对数组的约束
interface UserArr{
    [index:number]:string
}
var arr:UserArr=['aaa','bbb'];
console.log(arr[0]);
var arr:UserArr=[123,'bbb'];  /*错误*/
console.log(arr[0]);
//可索引接口 对对象的约束
interface UserObj{
    [index:string]:string
}
var arr:UserObj={name:'张三'};

//类类型接口:对类的约束  和   抽象类抽象有点相似    
interface Animal{
    name:string;
    eat(str:string):void;
}
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():viod;
}
interface Person extends Animal{
    work():viod;
}
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()


interface Animal{
    eat():viod;
}
interface Person extends Animal{
    work():viod;
}
class Programmer{
    public name:string;
    constructor(name:string){
        this.name = name
    }
    coding(code:string){
        console.log(this.name+code)
    }
}
class Web extends Proprammer 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代码')
泛型:
泛型:软件工程中,我们不仅要创建一致的定义良好的API,同时也要考虑可重用性。 组件不仅能够支持当前的数据类型,同时也能支持未来的数据类型,这在创建大型系统时为你提供了十分灵活的功能。

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

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

//只能返回string类型的数据
function getData(value:string):string{
    retrun value;
}

//同时返回 string类型 和number类型       any可以解决这个问题
function getData(value:any):any{
    return '哈哈哈';
}
getData(123);
getData('str');

//any放弃了类型检查,
//传入什么 返回什么。比如:传入number 类型必须返回number类型  传入 string类型必须返回string类型

function getData(value:any):any{   //传入的参数类型和返回的参数类型可以不一致
   return '哈哈哈'; 
}

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


function getData<T>(value:T):T{    // T表示泛型,具体什么类型是调用这个方法的时候决定的
     return value;
}
getData<number>(123);
getData<string>('1214231');
getData<number>('123');       /*错误的写法*/  

function getData<T>(value:T):any{
     return '2145214214';
}
getData<number>(123);  //参数必须是number
getData<string>('这是一个泛型');


// 泛型类:比如有个最小堆算法,需要同时支持返回数字和字符串 a  -  z两种类型。  通过类的泛型来实现
class MinClass{
    public list:number[]=[];
    add(num:number){
        this.list.push(num)
    }
    min():number{
        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 m=new MinClass();
m.add(3);
m.add(22);
m.add(23);
m.add(6);
m.add(7);
alert(m.min());

//类的泛型
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())       //  1

var m2=new MinClas<string>();   /*实例化类 并且制定了类的T代表的类型是string*/

m2.add('c');
m2.add('a');
m2.add('v');
alert(m2.min())      //  a
泛型接口:

函数类型接口:
interface ConfigFn{
    (value1:string,value2:string):string;
}
var setData:ConfigFn=function(value1:string,value2:string):string{
    return value1+value2;
}
setData('name','张三');

//1、泛型接口

interface ConfigFn{
     <T>(value:T):T;
 }
 var getData:ConfigFn=function<T>(value:T):T{
     return value;
 }
getData<string>('张三');
getData<string>(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)  //错误
泛型类:

泛类:泛型可以帮助我们避免重复的代码以及对不特定数据类型的支持(类型校验),下面我们看看把类当做参数的泛型类

1、定义个类
2、把类作为参数来约束数据传入的类型 

//比如有个最小堆算法 普通类型
 class MinClass{
     public list:number[]=[];
     add(num:number){
         this.list.push(num)
     }
     min():number{
         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 MinClass();   
 m1.add(11);
 m1.add(3);
 m1.add(2);
 alert(m1.min())

//类的泛型
 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())

/*
定义一个User的类这个类的作用就是映射数据库字段  
然后定义一个 MysqlDb的类这个类用于操作数据库   
然后把User类作为参数传入到MysqlDb中
var user=new User({
    username:'张三',
    password:'123456'
})
var Db=new MysqlDb();
Db.add(user);
*/

//把类作为参数来约束数据传入的类型 

 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<User>();
 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;
    }
}
//增加操作
 var a=new ArticleCate({
     title:'分类',
     desc:'1111',
     status:1
 });

// //类当做参数的泛型类
 var Db=new MysqlDb<ArticleCate>();
 Db.add(a);

//修改数据
var a=new ArticleCate({
        title:'分类111',
        desc:'2222'      
});

a.status=0;
var Db=new MysqlDb<ArticleCate>();
Db.updated(a,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<User>(); //类作为参数来约束数据传入的类型 
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);
命名空间:
    在代码量较大的情况下,为了避免各种变量命名相冲突,可将相似功能的函数、类、接口等放置到命名空间内
    同Java的包、.Net的命名空间一样,TypeScript的命名空间可以将代码包裹起来,只对外暴露需要在外部访问的对象。命名空间内的对象通过export关键字对外暴露。

命名空间和模块的区别:
    命名空间:内部模块,主要用于组织代码,避免命名冲突。
    模    块:ts的外部模块的简称,侧重代码的复用,一个模块里可能会有多个命名空间。

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 class Cat implements Animal {
        name: string;
        constructor(theName: string) {
            this.name = theName;
        }
        eat() {
            console.log(`${this.name} 吃猫粮。`);
        }
    }   

}

namespace B{
    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 class Cat implements Animal {
        name: string;
        constructor(theName: string) {
            this.name = theName;
        }
        eat() {
            console.log(`${this.name} 在吃猫粮。`);
        }
    }   
}
var c=new B.Cat('小花');
c.eat();


import {A,B} from './modules/animal';
var d=new A.Dog('小黑');
d.eat();

var dog=new B.Dog('小花');
dog.eat();
//animal.ts  文件
export 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 class Cat 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() {
            console.log(`${this.name} 在吃狗粮。`);
        }
    }

    export class Cat implements Animal {
        name: string;
        constructor(theName: string) {
            this.name = theName;
        }

        eat() {
            console.log(`${this.name} 在吃猫粮。`);
        }
    }   
}
装饰器:装饰器是一种特殊类型的声明,它能够被附加到类声明,方法,属性或参数上,可以修改类的行为。

    通俗的讲装饰器就是一个方法,可以注入到类、方法、属性参数上来扩展类、属性、方法、参数的功能。
    常见的装饰器有:类装饰器、属性装饰器、方法装饰器、参数装饰器
    装饰器的写法:普通装饰器(无法传参) 、 装饰器工厂(可传参)
    装饰器是过去几年中js最大的成就之一,已是Es7的标准特性之一

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


//1.1 类装饰器:普通装饰器(无法传参)
        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();

//1.2 类装饰器:装饰器工厂(可传参)

        function logClass(params:string){
            return function(target:any){
                console.log(target);
                console.log(params);
                target.prototype.apiUrl=params;
            }
        }
        @logClass('http://www.baidu.com/api')
        class HttpClient{
            constructor(){
            }
            getData(){
            }
        }

        var http:any=new HttpClient();
        console.log(http.apiUrl);
       
1、类装饰器 

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

        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、属性装饰器

        属性装饰器表达式会在运行时当作函数被调用,传入下列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);
            console.log(attr);
            target[attr]=params;
        }
    }
    @logClass('xxxx')
    class HttpClient{
        @logProperty('http://baidu.com')
        public url:any |undefined;
        constructor(){
        }
        getData(){
            console.log(this.url);
        }
    }
    var http=new HttpClient();
    http.getData();

    3、方法装饰器
        它会被应用到方法的 属性描述符上,可以用来监视,修改或者替换方法定义。

        方法装饰会在运行时传入下列3个参数:
            1、对于静态成员来说是类的构造函数,对于实例成员是类的原型对象。
            2、成员的名字。
            3、成员的属性描述符。

    4、方法参数装饰器
        参数装饰器表达式会在运行时当作函数被调用,传入下列3个参数:

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

        方法装饰会在运行时传入下列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.baidu.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.baidu.com')
            getData(...args:any[]){
                console.log(args);
                console.log('我是getData里面的方法');
            }
        }
        var http=new HttpClient();
        http.getData(123,'xxx');

    4、方法参数装饰器 

        参数装饰器表达式会在运行时当作函数被调用,可以使用参数装饰器为类的原型增加一些元素数据 ,传入下列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.baidu.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();

 

  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值