一 , 交叉类型(操作符 & ):
代码 :
function extend<T, U>(first: T, second: U): T & U { let result = <T & U>{}; for (let id in first) { (<any>result)[id] = (<any>first)[id]; } for (let id in second) { if (!result.hasOwnProperty(id)) { (<any>result)[id] = (<any>second)[id]; } } return result; } class Person { constructor(public name: string) { } } interface Loggable { log(): void; } class ConsoleLogger implements Loggable { log() { console.log(`AAAAA`); } } let jim = extend(new Person("Jim"), new ConsoleLogger()); let n = jim.name; console.log(`this is name : ${n}`); jim.log();
编译及结果:
可以看出jim既有Person的成员 , 也有ConsolerLogger的成员 . 交叉类型既是将此2种类型合并在一起使用:编译成的JS如下:
function extend(first, second) { var result = {}; for (var id in first) { result[id] = first[id]; } for (var id in second) { if (!result.hasOwnProperty(id)) { result[id] = second[id]; } } return result; } var Person = (function () { function Person(name) { this.name = name; } return Person; }()); var ConsoleLogger = (function () { function ConsoleLogger() { } ConsoleLogger.prototype.log = function () { console.log("AAAAA"); }; return ConsoleLogger; }()); var jim = extend(new Person("Jim"), new ConsoleLogger()); var n = jim.name; console.log("this is name : " + n); jim.log();
二,联合类型(操作符 | )
abstract class Monster{ public tpid : number; public name : string; public abstract attack:()=>string; constructor( tpid : number , name : string ){ this.tpid = tpid; this.name = name; } } class Godzilla extends Monster{ constructor(tpid : number){ super( tpid , `Godzilla` ); } //实现attack方法 public attack:()=>string=function(){ return `id : ${this.tpid} ,name : ${this.name} -> can fire`; } } class Medusa extends Monster{ constructor(tpid : number){ super(tpid,`Medusa`); } public attack:()=>string=function(){ return `id : ${this.tpid} , name : ${this.name} -> can turn to stone`; } } enum Monster_Type{ Godzilla = 0,//哥斯拉 Medusa = 1,//美杜莎 } //!important //使用联合类型 //因为返回参数可能是哥斯拉 也可能是美杜莎 所以使用联合类型(多选一) let create_monster : ( type : Monster_Type , tpid : number ) => Godzilla | Medusa = function( ty , id ){ switch ( ty ){ case Monster_Type.Godzilla: return new Godzilla(id); case Monster_Type.Medusa: return new Medusa(id); } return null; }; let gsl : Godzilla = create_monster( Monster_Type.Godzilla , 1 ); console.log( `gsl :: ${gsl.attack()}` ); let mds : Medusa = create_monster( Monster_Type.Medusa , 2 ); console.log( `mds :: ${mds.attack()}` );
上述代码 : create_monster方法的返回类型使用了联合类型
得到结果:
做一个测试 , 如果联合参数列表中没有AA类型 , 如果我们强制返回AA:
abstract class Monster{ public tpid : number; public name : string; public abstract attack:()=>string; constructor( tpid : number , name : string ){ this.tpid = tpid; this.name = name; } } class Godzilla extends Monster{ constructor(tpid : number){ super( tpid , `Godzilla` ); } //实现attack方法 public attack:()=>string=function(){ return `id : ${this.tpid} ,name : ${this.name} -> can fire`; } } class Medusa extends Monster{ constructor(tpid : number){ super(tpid,`Medusa`); } public attack:()=>string=function(){ return `id : ${this.tpid} , name : ${this.name} -> can turn to stone`; } } class AA{ } enum Monster_Type{ Godzilla = 0,//哥斯拉 Medusa = 1,//美杜莎 AA = 2 } //使用联合类型(AA并没有被加入到联合类型 (返回类型中)) Error //因为返回参数可能是哥斯拉 也可能是美杜莎 所以使用联合类型(多选一) let create_monster : ( type : Monster_Type , tpid : number ) => Godzilla | Medusa = function( ty , id ){ switch ( ty ){ case Monster_Type.Godzilla: return new Godzilla(id); case Monster_Type.Medusa: return new Medusa(id); case Monster_Type.AA: return new AA(); } return null; }; let gsl : Godzilla = create_monster( Monster_Type.Godzilla , 1 ); console.log( `gsl :: ${gsl.attack()}` ); let mds : Medusa = create_monster( Monster_Type.Medusa , 2 ); console.log( `mds :: ${mds.attack()}` );
编译报错:
这里需要注意一点 : 代码如下
abstract class Monster{ public tpid : number; public name : string; public abstract attack:()=>string; constructor( tpid : number , name : string ){ this.tpid = tpid; this.name = name; } } /** * 哥斯拉 */ class Godzilla extends Monster{ constructor(tpid : number){ super( tpid , `Godzilla` ); } //实现attack方法 public attack:()=>string=function(){ return `id : ${this.tpid} ,name : ${this.name} -> can fire`; } //实现喷火技能 public fire:()=>string=function(){ return `i can breathe fire`; } } /** * 美杜莎 */ class Medusa extends Monster{ constructor(tpid : number){ super(tpid,`Medusa`); } //实现attack方法 public attack:()=>string=function(){ return `id : ${this.tpid} , name : ${this.name} -> can turn to stone`; } //实现石化技能 public stone:()=>string=function(){ return `I can turn you into a stone`; } } /** * 怪物类型枚举 */ enum Monster_Type{ Godzilla = 0,//哥斯拉 Medusa = 1//美杜莎 } //使用联合类型 //因为返回参数可能是哥斯拉 也可能是美杜莎 所以使用联合类型(多选一) let create_monster : ( type : Monster_Type , tpid : number ) => Godzilla | Medusa = function( ty , id ){ switch ( ty ){ case Monster_Type.Godzilla: return new Godzilla(id); case Monster_Type.Medusa: return new Medusa(id); } return null; }; /* function create_monster( type : Monster_Type , tpid : number ) : Godzilla | Medusa{ switch ( type ){ case Monster_Type.Godzilla: return new Godzilla(tpid); case Monster_Type.Medusa: return new Medusa(tpid); } return null; } */ let gsl = create_monster( Monster_Type.Godzilla , 1 ); console.log( `gsl :: ${gsl.attack()}` ); let mds : Medusa = create_monster( Monster_Type.Medusa , 2 ); console.log( `mds :: ${mds.attack()}` );
编译报错如下:
解决方案有2种 :
① , 将 ":Medusa"去掉(如上图) , 因为Godzilla类和Medusa类不兼容 . 而返回类型使用了联合类型.如果有"Medusa" ,他会检测 Godzilla类和Medusa类的兼容性而报错.
② , 将Godzilla类里面的方法fire 及 Medusa里面的方法stone去掉,以使他们兼容 . 这时可以将":Medusa"加上.
三,保护类型
abstract class Monster{ public tpid : number; public name : string; public abstract attack:()=>string; constructor( tpid : number , name : string ){ this.tpid = tpid; this.name = name; } } /** * 哥斯拉 */ class Godzilla extends Monster{ constructor(tpid : number){ super( tpid , `Godzilla` ); } //实现attack方法 public attack:()=>string=function(){ return `id : ${this.tpid} ,name : ${this.name} -> can fire`; } //实现喷火技能 public fire:()=>string=function(){ return `i can breathe fire`; } } /** * 美杜莎 */ class Medusa extends Monster{ constructor(tpid : number){ super(tpid,`Medusa`); } //实现attack方法 public attack:()=>string=function(){ return `id : ${this.tpid} , name : ${this.name} -> can turn to stone`; } //实现石化技能 public stone:()=>string=function(){ return `I can turn you into a stone`; } } /** * 怪物类型枚举 */ enum Monster_Type{ Godzilla = 0,//哥斯拉 Medusa = 1//美杜莎 } //使用联合类型 //因为返回参数可能是哥斯拉 也可能是美杜莎 所以使用联合类型(多选一) let create_monster : ( type : Monster_Type , tpid : number ) => Godzilla | Medusa = function( ty , id ){ switch ( ty ){ case Monster_Type.Godzilla: return new Godzilla(id); case Monster_Type.Medusa: return new Medusa(id); } return null; }; /* function create_monster( type : Monster_Type , tpid : number ) : Godzilla | Medusa{ switch ( type ){ case Monster_Type.Godzilla: return new Godzilla(tpid); case Monster_Type.Medusa: return new Medusa(tpid); } return null; } */ let gsl = create_monster( Monster_Type.Godzilla , 1 ); //console.log( `gsl :: ${gsl.attack()}` ); // let mds = create_monster( Monster_Type.Medusa , 2 ); //console.log( `mds :: ${mds.attack()}` ); console.log((<Godzilla>gsl).fire());//(<Godzilla>gsl).fire console.log((<Medusa>mds).stone());
结果:
如上述代码 :
let gsl = create_monster( Monster_Type.Godzilla , 1 );
let mds = create_monster( Monster_Type.Medusa , 2 );
gsl 及 mds 都没有类型的声明. 如果要调用他们的技能 , gsl只能调用fire方法 , 而mds只能调用stone方法.我们程序员可以给这样的类型一个相当于强制装换的方案 如 : (<Godzilla>gsl).fire这样的写法很少见.记住就好.
四,索引类型:
function pluck<T, K extends keyof T>(o: T, names: K[]): T[K][] { return names.map(n => o[n]); } interface Person { name: string; age: number; add:( x : number , y : number ) => number; } let person: Person = { name: 'Jarid', age: 35, add:( x : number , y : number )=>{ return x + y ;}, }; let strings: Function[] = pluck(person, ['add']); console.log( ` ${ strings[0](1,2) } ` );
结果:
keyof T 返回T的公共成员联合 , 如:
function pluck<T, K extends keyof T>(o: T, names: K[]): T[K][] { return names.map(n => o[n]); } interface Person { name: string; age: number; add:( x : number , y : number ) => number; } let person: Person = { name: 'Jarid', age: 35, add:( x : number , y : number )=>{ return x + y ;}, }; let strings: Function[] = pluck(person, ['add']); //console.log( ` ${ strings[0](1,2) } ` ); //获取属性值 function getProperty<T, K extends keyof T>(o: T, name: K): T[K] { return o[name]; // o[name] is of type T[K] } let a : string = getProperty( person , 'name' ); console.log(a); let b : Function = getProperty( person , 'add' ); console.log( `${b(2,3)}` );
结果:
请发表评论