一、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();