一.介绍和安装
1. 安装相关
安装Typescript
npm install -g typescript
cnpm install -g typescript
yarn global add typescript
安装cnpm
npm install -g cnpm --registry=registry.npm.taobao.org
安装 yarn
npm install -g yarn
cnpm install -g yarn
2. 检测是否安装成功
tsc -v 如果有版本号就安装成功了。
3. 配置自动编译ts文件
使用tsc --init 生成tsconfig.json文件
修改tsconfig.json中的outDir输出文件路径
点击vscode - 终端 - 运行任务 - typescript - tsc:监视tsconfig.json
二.数据类型(指定完数据类型之后改成别的类型会报错)
1.布尔类型(boolean)
let flag:boolean = true;把flag改成别的类型会报错
注意,使用构造函数 Boolean 创造的对象不是布尔值:
let createdByNewBoolean: boolean = new Boolean(1);
// Type 'Boolean' is not assignable to type 'boolean'. // 'boolean' is a primitive, but 'Boolean' is a wrapper object. Prefer using 'boolean' when possible.
事实上 new Boolean() 返回的是一个 Boolean 对象:
let createdByNewBoolean: Boolean = new Boolean(1);
直接调用 Boolean 也可以返回一个 boolean 类型:
let createdByBoolean: boolean = Boolean(1);
注意区分大小写
2.数字类型(number)
let num:number = 123; number = 456;
// ES6 中的二进制表示法
let binaryLiteral: number = 0b1010;
// ES6 中的八进制表示法
let octalLiteral: number = 0o744;
3.字符串类型(string)
let str:string = '123'
4.数组类型(array)
es中定义数组三种方法:
第一种方式:let arr:number[] = [1,2,3];
第二种方式(泛型<>):let arr:Array《number》 = [1,2,3];
第三种方式:let arr:any[] = [1,2,'3','4'];
5.元祖类型(tuple) 属于数组的一种 给数组中每个位置指定一个类型
let arr:[string,number,boolean] = ['ts',1,true]; 如果值都是字符串 报错
6.枚举类型(enum) 如果标识符没有赋值 它的值就是下标 如果赋值了 之后的值递增
enum 枚举名{
标识符[=整型常数]
}
enum Flag {
success = 1,
error = 2
}
let s:Flag = Flag.success; //console.log(s);1
enum Color{blue,red,'orange'};
let c:Color = Color.red; //console.log(c);//1
enum Color {red,blue=5,orange};
let c:Color = Color.red; //0
let c:Color = Color.orange; //6
7.任意类型(any)
let num:any = 123; num = 'str';
任意类型的用途:
let oBox:any = document.getElementById('box')';//如果不指定类型会报错
oBox.style.color = 'red';
在任意值上访问任何属性都是允许的:
let anyThing: any = 'hello';
console.log(anyThing.myName);
console.log(anyThing.myName.firstName);
也允许调用任何方法:
let anyThing: any = 'Tom';
anyThing.setName('Jerry');
anyThing.setName('Jerry').sayHello();
anyThing.myName.setFirstName('Cat');
可以认为,声明一个变量为任意值之后,对它的任何操作,返回的内容的类型都是任意值。 变量如果在声明的时候,未指定其类型,那么它会被识别为任意值类型:
8.null undefined(定义没有赋值就是undefined)
undefined 类型的变量只能被赋值为 undefined,null 类型的变量只能被赋值为 null
let num:number; console.log(num); //报错
let num:undefined; console.log(num);//undefined
let num:number | undefined; num = 123; console.log(num);//123
let num:null; num = null;
与 void 的区别是,undefined 和 null 是所有类型的子类型。也就是说 undefined 类型的变量,可以赋值给 number 类型的变量:
// 这样不会报错
let num: number = undefined;
// 这样也不会报错
let u: undefined;
let num: number = u;
而 void 类型的变量不能赋值给 number 类型的变量:
let u: void;
let num: number = u;
// Type 'void' is not assignable to type 'number'.
类型推论:如果定义的时候没有赋值,不管之后有没有赋值,都会被推断成 any 类型而完全不被类型检查
9.void类型:表示没有任何类型,一般用于定义方法的时候方法没有返回值
function run():void{ console.log('run); } run();
function run():number{ return 123; } run();
声明一个 void 类型的变量没有什么用,因为你只能将它赋值为 undefined 和 null:
let unusable: void = undefined;
10.never类型:是其他类型(包括null和undefined)的子类型,代表不会出现的值。声明nerer的变量只能被never类型赋值。
let a:undefined; a = undefined;
let b:null; b = null;
let a:never; a=123;//报错
a=(()=>{throw new Error('错误')})(); //正确
三:函数
1.函数定义
//函数声明方法:
//具名函数
function run():string{
return 'run';
}
//匿名函数:(函数表达式)
var fun = funciton():number{
return 123;
}
//定义方法传参:
function getInfo(name:string, age:number):string{
return `${name} --- ${age}`
}
getInfo('zhangsan',20);
var getInfo = function(name:string, age:number):string{
return `${name} --- ${age}`
}
getInfo('zhangsan',40);
//没有返回值的方法
function run:void(){
console.log('run');
}
run();
2.方法可选参数
es5里面方法的是实参跟行参可以不一样,但是ts中必须一样,如果不一样需要配置可选参数
function getInfo(name:string, age?:number):string{
if(age){
return `${name} --- ${age}`
}else{
return `${name} --- 年龄保密`
}
}
getInfo('zhangsan',20);//zhangsan --- 20;
getInfo('zhangsan');//zhangsan --- 年龄保密;
注意:可选参数必须配置到参数的最后面
3.默认参数
es5里面没法设置默认参数,es6和ts中都可以设置默认参数
function getInfo(name:string, age:number=20):string{
if(age){
return `${name} --- ${age}`
}else{
return `${name} --- 年龄保密`
}
}
getInfo('zhangsan');//zhangsan --- 20
4.剩余参数(三点运算符接受行参传过来的值)
function sum(...result:number[]):number{
var sum = 0;
for(let i = 0;i<result.length;i++){
sum+=result[i]
}
return sum;
}
sum(1,2,3,4);//10
//把1赋值给a 剩余的赋值给result
function sum(a:number, ...result:number[]):number{
var sum = a;
for(let i = 0;i<result.length;i++){
sum+=result[i]
}
return sum;
}
sum(1,2,3,4);//10
5.函数重载
两个或者两个以上的同名函数,但它们传入不同的参数,执行不同的结果
function getInfo(name:string):string;
function getInfo(age:number):number;
function getInfo(str:any):any{
if(typeof str === 'string'){
return '我叫:'+str
}else{
return '我的年龄:'+str;
}
}
getInfo('张三');//我叫张三
getInfo(20);//我的年龄20
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
}
}
6.箭头函数
箭头函数里面的this指向上下文
7.用接口定义函数的形状
我们也可以使用接口的方式来定义一个函数需要符合的形状:
interface SearchFunc {
(source: string, subString: string): boolean;
}
let mySearch: SearchFunc;
mySearch = function(source: string, subString: string) {
return source.search(subString) !== -1;
}
四:类
1.es5中的类 静态方法 继承
类:属性+方法+原型链
function Person{
this.name = '张三';//属性
this.age = 20;
//构造函数里面增加方法
this.run = function(){ //实例方法 必须new之后才能调用
alert(this.name+'在运动');
}
}
//静态方法
Person.getInfo = function(){
alert('我是静态方法')
}
//原型链下面定义属性跟方法
原型链上面的属性会被多个实例共享 构造函数不会
Person.prototype.sex = '男';
Person.prototype.work = function(){
alert(this.name+'在工作');
}
//实例化
var p = new Person();
console.log(p.name);//张三
console.log(p.age);//20
p.run();//张三在运动
p.work();//张三在工作
//调用静态方法
Person.getInfo(); //我是静态方法
继承:
对象冒充继承:可以继承构造函数里面的属性和方法,但是没法继承原型链上面的属性和方法 Person.call(this);
function Person{
this.name = '张三';
this.age = 20;
this.run = function(){
alert(this.name+'在运动');
}
}
Person.prototype.sex = '男';
Person.prototype.work = function(){
alert(this.name+'在工作');
}
//web类继承Person类 原型链+对象冒充组合继承模式
function Web(){
Person.call(this); //对象冒充
}
var w = new Web();
w.run();/c张三在运动 对象冒充可以继承构造函数里面的属性和方法
w.work(); //报错 对象冒充没法继承原型链上面的属性和方法
原型链继承:可以继承构造函数里面的属性和方法 也可以继承原型链上面的属性和方法 web.prototype = new Person(); 但是实例化子类的时候没法给父类传参
function Person{
this.name = '张三';
this.age = 20;
this.run = function(){
alert(this.name+'在运动');
}
}
Person.prototype.sex = '男';
Person.prototype.work = function(){
alert(this.name+'在工作');
}
//web类继承Person类 原型链继承模式
function Web(){
}
Web.prototype = new Person();
var w = new Web();
w.run();//张三在运动
w.work();//张三在工作
//原型链实现继承的问题
function Person(name,age){
this.name = name;
this.age = age;
this.run = function(){
alert(this.name+'在运动');
}
}
Person.prototype.sex = '男';
Person.prototype.work = function(){
alert(this.name+'在工作');
}
//web类继承Person类 原型链继承模式
function Web(name,age){
}
Web.prototype = new Person();
var w = new Web('李四',20);//实例化子类的时候没办法给父类传承
w.run();//undefined在运动
w.work();//undefined在工作
原型链+构造函数组合继承:完美解决上面的问题
function Person(name,age){
this.name = name;
this.age = age;
this.run = function(){
alert(this.name+'在运动');
}
}
Person.prototype.sex = '男';
Person.prototype.work = function(){
alert(this.name+'在工作');
}
function Web(name,age){
Person.call(this,name,age);//对象冒充继承 实例化子类可以给父类传承
}
Web.prototype = new Person();
var w = new Web('李四',20);
w.run();//李四在运动
w.work();//李四在工作
另一种方式:
function Person(name,age){
this.name = name;
this.age = age;
this.run = function(){
alert(this.name+'在运动');
}
}
Person.prototype.sex = '男';
Person.prototype.work = function(){
alert(this.name+'在工作');
}
function Web(name,age){
Person.call(this,name,age);//对象冒充继承 实例化子类可以给父类传承 可以继承构造函数的属性和方法
}
Web.prototype = Person.prototype;//因为上面对象冒充已经继承了构造函数的。这边只需要继承原型链的
var w = new Web('李四',20);
w.run();//李四在运动
w.work();//李四在工作
2.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;//定义属性 前面省略了public关键词
constructor(name:string){//构造函数 实例化类的时候触发的方法
this.name = name;
},
getName():string{
return this.name;
},
setName(name:string):void{
this.name = name;
}
}
var p = new Person('张三');
p.getName();//张三
p.setName('李四');
p.getName();//李四
继承 extends super
class Person{
name:string;//定义属性 前面省略了public关键词
constructor(name:string){//构造函数 实例化类的时候触发的方法
this.name = name;
},
run():string{
return `${this.name}在运动`
}
}
class Web extends Person{
constructor(name:string){
super(name);//初始化父类的构造函数
},
}
var w = new Web('李四');
w.run();//李四在运动
继承的探讨 父类跟子类的方法一致 先在子类里面找 如果没有再去父类找
class Person{
name:string;//定义属性 前面省略了public关键词
constructor(name:string){//构造函数 实例化类的时候触发的方法
this.name = name;
},
run():string{
return `${this.name}在运动`
}
}
class Web extends Person{
constructor(name:string){
super(name);//初始化父类的构造函数
},
run():string{
return `${this.name}在运动-子类`
},
work(){
alert(`${this.name}在工作`)
}
}
var w = new Web('李四');
w.run();//李四在运动-子类
修饰符
public:公有 在类里面、子类、类外面都可以访问
class Person{
public name:string;
constructor(name:string){
this.name = name;
},
run():string{
return `${this.name}在运动`
}
}
class Web extends Person{
constructor(name:string){
super(name);
},
run():string{
return `${this.name}在运动-子类`
},
work(){
alert(`${this.name}在工作`)
}
}
//类外部访问
var p = new Person('hahaha');
p.name;//hahaha
protected:保护类型 在类里面、子类里面都可以访问,在类外部没法访问
class Person{
protected name:string;
constructor(name:string){
this.name = name;
},
run():string{
return `${this.name}在运动`
}
}
class Web extends Person{
constructor(name:string){
super(name);
},
work(){
alert(`${this.name}在工作`)
}
}
//子类里面调用
var w = new Web('hahaha1');
w.work();//hahaha1在工作
//在外部里面调用
var p = new Person('111');
p.name;//报错
//当前类里面调用
p.run();//hahaha1在运动
当构造函数修饰为 protected 时,该类只允许被继承,不允许实例化
class Animal {
public name;
protected constructor (name) {
this.name = name;
}
}
class Cat extends Animal {
constructor (name) {
super(name);
}
}
let a = new Animal('Jack');
// index.ts(13,9): TS2674: Constructor of class 'Animal' is protected and
only accessible within the class declaration.
private:私有 在类里面可以访问,子类、类外部都无法访问
属性如果不加修饰符,默认就是公有public
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(){
alert(`${this.name}在工作`);//报错
}
}
var w = new Web('hahaha1');
//在外部里面调用
var p = new Person('111');
p.name;//报错
//当前类里面调用
p.run();//hahaha1在运动
当构造函数修饰为 private 时,该类不允许被继承或者实例化:
class Animal {
public name;
private constructor (name) {
this.name = name;
}
}
class Cat extends Animal {
constructor (name) {
super(name);
}
}
let a = new Animal('Jack');
// index.ts(7,19): TS2675: Cannot extend a class 'Animal'. Class
constructor is marked as private.
// index.ts(13,9): TS2673: Constructor of class 'Animal' is private and
only accessible within the class declaration
静态属性 静态方法(不需要实例化,可直接调用,但里面没法直接调用类里面的属性 只能把属性变成静态属性)
class Person{
public name:string;
public age:number = 20;
//静态属性
static sex = '男';
constructor(name){
this.name = name;
},
run():void{
alert(this.name);
},
static print(){//静态方法
alert('print');
},
//静态方法 里面没法直接调用类里面的属性
static print1(){
alert('print1 '+this.age);
},
//静态方法 里面没法直接调用类里面的属性 只能把属性变成静态属性
static print2(){
alert('print2 '+ Person.sex);
}
}
Person.print();//print
Person.print1();//print1 undefined
Person.print2();//print2 男
多态:多态属于继承 父类定义一个方法不去实现 让继承他的子类去实现 每一个子类有不同的表现
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+'吃老鼠'
}
}
抽象类:它是提供其他类继承的基类,不能直接被实例化;用abstract关键字定义;抽象类中的抽象方法不包含具体实现并且必须派生类中实现;抽象方法只能放在抽象类中;用来定义标准。标准:Animal这个类要求他的子类必须包含eat方法
基类:父类 派生类:子类
abstract class Animal{
public name:string;
constructor(name:string){
this.name = name;
},
abstract eat():any;//不包含具体实现并且必须派生类中实现
run(){
console.log('其他方法可以不实现');
}
}
class Dog extends Animal{
constructor(name:any){
super(name);
},
//抽象类的子类必须实现抽象类里面的抽象方法
eat(){
return this.name+'吃粮食'
}
}
class Cat extends Animal{
constructor(name:any){
super(name);
}
}
var a = new Animal();//报错 不能直接被实例化
var d = new Dog('小花花');
d.eat();//小花花吃粮食
var c = new Cat('小花花');
c.eat();//报错 必须实现eat方法
五:接口(定义标准)
它是对行为的抽象,而具体如何行动需要由类(classes)去实现(implement)。
除了可用于对类的一部分行为进行抽象以外,也常用于对「对象的形状(Shape)」进行描述。
赋值的时候,变量的形状必须和接口的形状保持一致。多一些属性少一些属性都是不允许的,如果不希望完全匹配一个形状,可以用可选属性,但是仍然不允许添加未定义的属性
1.属性接口(对批量方法传入参数进行json的约束) 参数的顺序可以不一样
//传入对象的约束
interface FullName{
firstName: string;//注意;结束
secondName: string;
}
function printName(name:FullName){
//必须传入对象 firstName secondName
console.log(name.firstName+'--'+name.secondName)
}
printName('123');//报错
printName({
age:20,
firstName:'张',
secondName:'三'
})//报错 多传了20 但是赋值给对象就不报错了 如下
var obj = {
age:20,
firstName:'张',
secondName:'三'
}
printName(obj); //这样的方式不会报错
//传入对象的约束
interface FullName{
firstName: string;//注意;结束
secondName: string;
}
function printInfo(info:FullName){
//必须传入对象 firstName secondName
console.log(info.firstName+'--'+info.secondName+'--'+info.age)
}
var obj = {
age:20,
firstName:'张',
secondName:'三'
}
printInfo(obj);//报错 FullName上没有age属性
2.接口可选属性
interface FullName{
firstName: string;
secondName?: string;
}
function printName(name:FullName){
//必须传入对象 firstName
console.log(name)
}
printName({
firstName:'张'
})
3.接口任意属性
有时候我们希望一个接口允许有任意的属性,可以使用如下方式:
interface Person {
name: string;
age?: number;
[propName: string]: any;
}
let tom: Person = {
name: 'Tom',
gender: 'male'
};
需要注意的是,一旦定义了任意属性,那么确定属性和可选属性的类型都必须是它的类型的子集:
interface Person {
name: string;
age?: number;
[propName: string]: string;
}
let tom: Person = {
name: 'Tom',
age: 25,
gender: 'male'
};
// index.ts(3,5): error TS2411: Property 'age' of type 'number' is not assignable to string index type 'string'.
// index.ts(7,5): error TS2322: Type '{ [x: string]: string | number; name: string; age: number; gender: string; }' is not assignable to type 'Person'.
// Index signatures are incompatible.
// Type 'string | number' is not assignable to type 'string'.
// Type 'number' is not assignable to type 'string'.
上例中,任意属性的值允许是 string,但是可选属性 age 的值却是 number,number 不是 string 的子属性,所以报错了。
4.接口只读属性
有时候我们希望对象中的一些字段只能在创建的时候被赋值,那么可以用 readonly 定义只读属性:
interface Person {
readonly id: number;
name: string;
age?: number;
[propName: string]: any;
}
let tom: Person = {
id: 89757,
name: 'Tom',
gender: 'male'
};
tom.id = 9527;
// index.ts(14,5): error TS2540: Cannot assign to 'id' because it is a constant or a read-only property.
上例中,使用 readonly 定义的属性 id 初始化后,又被赋值了,所以报错了。
注意,只读的约束存在于第一次给对象赋值的时候,而不是第一次给只读属性赋值的时候:
interface Person {
readonly id: number;
name: string;
age?: number;
[propName: string]: any;
}
let tom: Person = {
name: 'Tom',
gender: 'male'
};
tom.id = 89757;
// index.ts(8,5): error TS2322: Type '{ name: string; gender: string; }' is not assignable to type 'Person'.
// Property 'id' is missing in type '{ name: string; gender: string; }'.
// index.ts(13,5): error TS2540: Cannot assign to 'id' because it is a constant or a read-only property.
上例中,报错信息有两处,第一处是在对 tom 进行赋值的时候,没有给 id 赋值。
第二处是在给 tom.id 赋值的时候,由于它是只读属性,所以报错了。
5.函数类型的接口:对方法传入的参数以及返回值进行约束 批量约束
//加密的函数类型接口
interface encrypt{
(key:string,value:string):string;
}
var md5:encrypt = function(key:string,value:string):string{
//模拟操作
return key+value;
}
md5('name','zhangsan');//namezhangsan
var sha1:encrypt = function(key:string,value:string):string{
//模拟操作
return key+'---'+value;
}
sha1('name','lisi');//name---lisi
6.可索引接口:数组、对象的约束(不常用)
//对数组的约束
interface UserArr{
[index:number]:string
}
var arr:UserArr = ['aaa','bbb'];
console.log(arr[0]);//aaa
//对对象的约束
interface UserObj{
[index:string]:string
}
var arr:UserObj = {
name:'lisan'
}
7.类类型接口:对类的约束 和抽象类有点相似 implements实现接口
interface Animal{
name:string,
eat(str:string):void;
}
class Dog implements Animal{
name:string;
constructor(name:string){
this.name = name;
},
eat(){//可以不传参数 但是必须实现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('老鼠');//小花吃老鼠
8.接口扩展:接口可以继承接口
interface Animal{
eat():void;
}
interface Person extends Animal{
work():void;
}
class Programmer{
name:string;
constructor(name:string){
this.name = name;
},
coding(code:string){
console.log(this.name+code);
}
}
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.work();//艺兴写代码
w.eat();//艺兴喜欢吃馒头
w.coding('写ts代码');//艺兴写ts代码
六:泛型:不仅能够支持当前的数据类型,同时也能支持未来的数据类型 传入的参数跟返回的参数一致
1.泛型函数
//T表示泛型 具体什么类型是调用这个方法的时候决定的
function getData<T>(value:T):T{
return value;
}
getData<number>(123);//123
getData<number>('123');//报错
function getData<T>(value:T):any{
return '122321';
}
getData<number>(123);//122321
getData<string>('这是一个泛型');//122321
2.泛型类
//实现一个最小值算法 支持返回数字跟字符串a-z两种类型
class MinClass<T>{
public list:T[] = [];
add(value:T):void{
this.list.push(value)
},
min():T{
var minNum = this.list[0];
for(let i = 0;i<this.list.length;i++){
if(minNum>this.list[i]){
minNum = this.list[i]
}
}
return minNum;
}
}
var m1 = new MinClass<number>();//实例化类 并且制定了类的T代表的类型是number
m1.add(1);
m1.add(2);
m1.add(13);
m1.min();//1
var m2 = new MinClass<string>();//实例化类 并且制定了类的T代表的类型是string
m2.add('a');
m2.add('p');
m2.add('z');
m2.min();//a
3.泛型接口
//第一种
interface configFn{
<T>(value:T):T;
}
var getData:configFn = function<T>(value:T):T{
return value;
}
getData<string>('lay');//lay
//第二种
interface configFn<T>{
(value:T):T;
}
function getData<T>(value:T):T{
return value;
}
var myGetData:configFn<string> = getData;
myGetData('lay');//lay
4.把类当作参数的泛型类 要实现泛型接口 这个类也应该是一个泛型类
class User{
username: string | undefined;
password: string | undefined;
}
class MysqlDb{
add(user: User):boolean{
console.log(user);
return true;
}
}
var u = new User();
u.username = '张三';
u.password = '131343';
var Db = new MysqlDb();
Db.add(u);
class ArticleCate{
title: string | undefined;
desc: string | undefined;
}
class MysqlDb{
add(info: ArticleCate):boolean{
console.log(info);
return true;
}
}
var a = new ArticleCate();
a.title = '国内';
a.desc = '国内新闻';
var Db = new MysqlDb();
Db.add(a);
以上代码重复 希望只封装一次就可以检验
*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
//操作数据库的泛型类
class MysqlDb<T>{
add(info: T):boolean{
console.log(info);
return true;
}
}
//想给user表增加数据
1.定义一个user类 和数据库就行映射
class User{
username: string | undefined;
password: string | undefined;
}
var u = new User();
u.username = '张三';
u.password = '131343';
var Db = new MysqlDb<User>();
Db.add(u);
2.定义一个ArticleCate类 和数据库就行映射
class ArticleCate{
title: string | undefined;
desc: string | undefined;
constructor(params:{
title: string | undefined,
desc: string | undefined
}){
this.title = params.title;
this.desc = params.desc;
}
}
var a = new ArticleCate({
title:'国内',
desc:'国内新闻'
});
var Db = new MysqlDb<ArticleCate>();
Db.add(a);
七:模块
1.单个暴露
export var url = 'xxx';
export funciton getData():any[]{ return [ {title:'111'} ] }
import {url, getData} from 'xxx';
getData();
2.多个暴露
export {url, getData};
import {url, getData} from 'xxx';
简化名称:as关键词
import {url, getData as get} from 'xxx';
get();
3.默认导出 一个模块只能有一个defalut导出
export default getData;
import getData from 'xxx';
八:命名空间(避免命名冲突 命名空间里面的类和方法是私有的 必须导出)
export namespace A{
interface Animal{
name:string,
eat(str:string):void;
}
export class Dog implements Animal{//命名空间里面的类和方法是私有的 必须导出
name:string;
constructor(name:string){
this.name = name;
},
eat(){//可以不传参数 但是必须实现eat方法
console.log(this.name+'吃粮食');
}
}
export class Cat implements Animal{
name:string;
constructor(name:string){
this.name = name;
},
eat(food:string){
console.log(this.name+'吃'+food);
}
}
}
export namespace B{
interface Animal{
name:string,
eat(str:string):void;
}
export class Dog implements Animal{//命名空间里面的类和方法是私有的 必须导出
name:string;
constructor(name:string){
this.name = name;
},
eat(){//可以不传参数 但是必须实现eat方法
console.log(this.name+'吃粮食');
}
}
export class Cat implements Animal{
name:string;
constructor(name:string){
this.name = name;
},
eat(){
console.log(this.name+'吃猫粮');
}
}
}
import {A,B} from 'xxx';
var d = new A.Dog('小黑');
d.eat();//小黑吃粮食
var c = new B.Dog('小花');
c.eat();//小花吃粮食1
九:装饰器:特殊的类型声明,它能够被附加到类声明,方法,属性或参数上,可以修改类的行为。通俗的讲就是一个方法。可以注入到类,方法,属性以及参数上来扩展
1.类装饰器:普通装饰器 不可传参(不修改类的前提下,扩展类的功能)
//装饰器
function logClass(params:any){
//params就是当前类
console.log(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();//我是run方法
2.类装饰器:装饰器工厂(可传参)
//装饰器
function logClass(params:string){
return function(target:any){
console.log(target);//就是当前类
console.log(params);//传入的参数 http://www.itying.com/api
//扩展属性
target.prototype.apiUrl = params;
//扩展方法
target.prototype.run = function(){
console.log('我是run方法');
}
}
}
//使用装饰器
@logClass('http://www.itying.com/api')//不能加分号;
class HttpClient{
constructor(){
},
getData(){
}
}
var http:any = new HttpClient();
console.log(http.apiUrl);//http://www.itying.com/api
http.run();//我是run方法
//重载构造函数
//装饰器
function logClass(target:any){
//target就是当前类
console.log(target);
return class extends target{
apiUrl:any = '我是修改后的数据';
getData(){
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();//我是修改后的数据---
3.属性装饰器
接受两个参数:
1.对于静态成员来说是类的构造函数,对于实例成员是类的原型对象
2.成员属性名
//类装饰器
function logClass(params:string){
return function(target:any){
console.log(target);//就是当前类
console.log(params);//xxx
}
}
//属性装饰器
function logProperty(params:any){
return function(target:any,attr:any){
console.log(target);//就是当前类的原型对象
console.log(attr);//url
target[attr] = params;//修改属性
}
}
//使用装饰器
@logClass('xxx')//不能加分号;
class HttpClient{
@logProperty('http://www.itying.com/api')
public url:any | undefined;
constructor(){
},
getData(){
console.log(this.url);
}
}
var http:any = new HttpClient();
http.getData();//http://www.itying.com/api
4.方法装饰器(用来监视、修改或者替换方法定义)
接受三个参数:
1.对于静态成员来说是类的构造函数,对于实例成员是类的原型对象
2.方法的名称
3.成员的属性描述符 方法的描述
//方法装饰器
function get(params: any){
return function(target:any,methodsName:any,desc:any){
console.log(target);//就是当前类的原型对象
console.log(methodsName);//getData
console.log(desc.value);//当前的方法
//扩展属性跟方法
target.apiUrl = 'xxx';
target.run = function(){
console.log('我是run方法');
}
//修改getData方法 把装饰器方法里面传入的所有参数改为string类型
//1.保存当前的方法
var oMethod = desc.value;
desc.value = function(...args:any[]){
args = args.map((value)=>{
return String(value)
})
oMethod.apply(this,args);//修改getData方法 如果没有这个就是替换getData方法
}
}
}
class HttpClient{
public url:any | undefined;
constructor(){
},
@get('http://www.itying.com/api')
getData(...args:any[]){
console.log(args);
console.log('我是getData里面的方法');
}
}
var http:any = new HttpClient();
console.log(http.apiUrl);//xxx
http.run();//我是run方法
http.getData(123,'xxx')//['123','xxx'] 我是getData里面的方法
5.方法参数表达式(为类的原型添加一些元素数据)
接受三个参数:
1.对于静态成员来说是类的构造函数,对于实例成员是类的原型对象
2.方法的名字
3.参数在函数参数中的索引
function logParams(params:any){
return function(target:any,methodName:any,paramsIndex:any){
console.log(params);//xxx
console.log(target);//原型对象
console.log(methodName);//getData
console.log(paramsIndex);//0
target.apiUrl = params;
}
}
class HttpClient{
public url:any | undefined;
constructor(){
},
getData(@logParams('xxxx') uuid:any){
console.log(uuid);//123456
}
}
var http:any = new HttpClient();
http.getData(123456);
console.log(http.apiUrl);//xxxx
6.执行顺序(属性>方法>方法参数>类;如果有多个同样的装饰器,先执行后面的)
//装饰器
function logClass1(params:any){
return function(target:any){
console.log('类装饰器1')
}
}
function logClass2(params:any){
return function(target:any){
console.log('类装饰器2')
}
}
function logAttribute(params?:string){
return funciton(target:any,attrName:any){
console.log('属性装饰器')
}
}
function logMethod(params?:string){
return funciton(target:any,methodName:any,desc:any){
console.log('方法装饰器')
}
}
function logParams1(params?:string){
return funciton(target:any,methodName:any,paramsIndex:any){
console.log('方法参数装饰器1')
}
}
function logParams2(params?:string){
return funciton(target:any,methodName:any,paramsIndex:any){
console.log('方法参数装饰器1')
}
}
//使用装饰器
@logClass1('http://baidu.com')
@logClass2('xxx')
class HttpClient{
@logAttribute()
public apiUrl: string | undefined;
constructor(){
},
@logMethod()
getData(){
return true;
},
setData(@logParams1() attr1:any,@logParams2() attr2:any){
}
}
var http:any = new HttpClient();
//属性装饰器 方法装饰器 方法参数装饰器2 方法参数装饰器1 类装饰器2 类装饰器1
十:数组的类型
在 TypeScript 中,数组类型有多种定义方式,比较灵活。
1.「类型 + 方括号」表示法
最简单的方法是使用「类型 + 方括号」来表示数组:
let fibonacci: number[] = [1, 1, 2, 3, 5];
数组的项中不允许出现其他的类型:
let fibonacci: number[] = [1, '1', 2, 3, 5];
// Type 'string' is not assignable to type 'number'.
数组的一些方法的参数也会根据数组在定义时约定的类型进行限制:
let fibonacci: number[] = [1, 1, 2, 3, 5];
fibonacci.push('8');
// Argument of type '"8"' is not assignable to parameter of type 'number'.
上例中,push 方法只允许传入 number 类型的参数,但是却传了一个 "8" 类型的参数,所以报错了。这里 "8" 是一个字符串字面量类型,会在后续章节中详细介绍。
2.数组泛型
我们也可以使用数组泛型(Array Generic) Array 来表示数组:
let fibonacci: Array<number> = [1, 1, 2, 3, 5];
3.用接口表示数组
interface NumberArray {
[index: number]: number;
}
let fibonacci: NumberArray = [1, 1, 2, 3, 5];
NumberArray 表示:只要索引的类型是数字时,那么值的类型必须是数字。
虽然接口也可以用来描述数组,但是我们一般不会这么做,因为这种方式比前两种方式复杂多了。
不过有一种情况例外,那就是它常用来表示类数组。
4.类数组
类数组(Array-like Object)不是数组类型,比如 arguments:
function sum() {
let args: number[] = arguments;
}
// Type 'IArguments' is missing the following properties from type 'number[]': pop, push, concat, join, and 24 more.
上例中,arguments 实际上是一个类数组,不能用普通的数组的方式来描述,而应该用接口:
function sum() {
let args: {
[index: number]: number;
length: number;
callee: Function;
} = arguments;
}
在这个例子中,我们除了约束当索引的类型是数字时,值的类型必须是数字之外,也约束了它还有 length 和 callee 两个属性。
事实上常用的类数组都有自己的接口定义,如 IArguments, NodeList, HTMLCollection 等:
function sum() {
let args: IArguments = arguments;
}
其中 IArguments 是 TypeScript 中定义好了的类型,它实际上就是:
interface IArguments {
[index: number]: any;
length: number;
callee: Function;
}
5.any 在数组中的应用
一个比较常见的做法是,用 any 表示数组中允许出现任意类型:
let list: any[] = ['xcatliu', 25, { website: 'http://xcatliu.com' }];
参考链接:
TypeScript安利指南 这个下面有各种传送门