接 上篇 。
1 /* ===============================类型断言====================================== */
2 /* C#中可以使用as或者强转的方法,虽然ts中也有类似的写法,但是类型断言
3 只会影响 TypeScript 编译时的类型,类型断言语句在编译结果中会被删除 */
4
5 // 基接口
6 class Animal {
7 constructor(readonly name: string) {
8 }
9 eat(): void {
10 console.log(`${ this .name} is eating`);
11 };
12 }
13 // 子接口们
14 class Dog extends Animal {
15 roar(): void {
16 console.log(`${ this .name} is wongwongwong`);
17 };
18 }
19 class Bird extends Animal {
20 fly(): void {
21 console.log(`${ this .name} is flying`);
22 };
23 }
24 class Fish extends Animal {
25 swim(): void {
26 console.log(`${ this .name} is swimming`);
27 };
28 }
29 // 参数使用父类可以接收所有子类
30 function letsEat(animal: Animal) {
31 animal.eat();
32 }
33 letsEat( new Dog("小鱼")); // 小白 is eating
34
35 // 在ts中,父类可以断言成子类,因为“狗狗肯定是动物”很好理解
36 function dog2Animal(xb: Dog) {
37 (xb as Animal).eat()
38 }
39
40 // 函数参数如果使用联合类型,那么可以调用其动物类的方法
41 function letsEat2(animal: Dog | Bird | Fish) {
42 animal.eat();
43 }
44 letsEat( new Fish("小白")); // 小白 is eating
45
46 // 那么想调用子类的方法的话,我们可以先进行类型断言,父类可以被断言为为子类!
47 // ?:那如果animal断言成Dog,但是animal的实际类型不是Dog,那会怎么样呢?
48 function letRoar(animal: Animal) {
49 (animal as Dog).roar();
50 }
51 function letsFly(animal: Dog | Bird | Fish) {
52 (animal as Bird).fly();
53 }
54 // 结果就是ts编译没问题,但是实际运行会报错
55 // letRoar(new Fish("小鱼")); //Error: animal.swim is not a function
56 // letsFly(new Dog("小白")); //Error: animal.fly is not a function
57
58 // 解决这个情况可以使用intanceof方法先判断
59 function letsPlay(animal: Dog | Bird | Fish) {
60 if (animal instanceof Dog) {
61 (animal as Dog).roar();
62 }
63 else if (animal instanceof Bird) {
64 (animal as Bird).fly();
65 } else if (animal instanceof Fish) {
66 (animal as Fish).swim();
67 }
68 }
69 letsPlay( new Bird("小鸟")); // 小白 is flying
70
71 // 总结(https://ts.xcatliu测试数据/basics/type-assertion)
72 // (1)联合类型可以被断言为其中一个类型;
73 // (2)父类可以被断言为子类;
74 // (3)任何类型都可以被断言为 any;
75 // (4)any 可以被断言为任何类型;
76 // 总之,若 A 兼容 B,那么 A 能够被断言为 B,B 也能被断言为 A
77 // 注意:类型断言不是类型转换
78
79
80 /* ===============================交叉类型====================================== */
81 // 交叉类型是将多个类型合并成一个类型的意思
82 // 例如, Person & Serializable & Loggable 这个类型的对象同时拥有了这三种类型的成员。
83
84 /* for-in语法:可以遍历一个对象中的所有属性,并以字典的读取方式获取属性的值,语法:
85 for (const prop in object) {
86 if (object.hasOwnProperty(prop)) {
87 const element = object[prop];
88 }
89 }
90 */
91
92 // 如何创建混入的一个方法
93 function extend<T1, T2 extends object>(type1: T1, type2: T2): T1 & T2 {
94 let result = <T1 & T2> {};
95
96 for (let prop in type1) {
97 (<any>result)[prop] = type1[prop];
98 }
99
100 for (let prop in type2) {
101 if (type2.hasOwnProperty(prop)) {
102 (<any>result)[prop] = (<any> type2)[prop]
103
104 }
105 }
106 return result;
107 }
108 // 在创建一个类类型
109 class Identity {
110 constructor(public gender: string, public birthDay: Date) {
111 }
112 }
113 // 将Dog类和Identity类进行交叉
114 let bd: Date = new Date('2015-09-07' );
115 let xb = extend( new Dog("小白"), new Identity("male" , bd));
116
117 console.log(xb.birthDay); // 2015-09-07
118 console.log(xb.gender); // male
119 xb.roar(); // 小白 is wongwongwong
120
121
122 /* ==============================可以为null的类型================================ */
123 // 默认情况下,类型检查器认为 null与 undefined可以赋值给任何类型。
124 // 按照JavaScript的语义,TypeScript会把 null和 undefined区别对待
125
126 let s = "foo" ;
127 // s = null; // 错误, 'null'不能赋值给'string'
128
129 let sn: string | null = "bar" ;
130 sn = null ; // 可以
131
132 // sn = undefined; // error, 'undefined'不能赋值给'string | null'
133
134 // 对于可为null类型的参数
135 function f(sn: string | null ): string {
136 if (sn == null ) {
137 return "default" ;
138 }
139 else {
140 return sn;
141 }
142 }
143 /* “短路运算符”写法:
144 function f(sn: string | null): string {
145 return sn || "default";
146 }
147 */
148
149
150 /* ==============================字符串字面量类型================================ */
151 // 字符串字面量:用来约束取值只能是某几个字符串中的一个。
152
153 type pet = 'dog' | 'bird' | 'fish' ;
154 function adoptPet(p: pet): Animal {
155 if (p === 'dog' ) {
156 return new Dog("小白" );
157 }
158 else if (p === 'bird' ) {
159 return new Bird("飞飞" );
160 }
161 else if (p === "fish" ) {
162 return new Fish("金金" );
163 }
164 else {
165 assertNever(p); // 这招叫“完整性检查”,自己体会,惊喜的是,如果前面条件判断有漏掉某个情形,这里是会报错的。
166 }
167 }
168 function assertNever(x: never): never {
169 throw new Error("Unexpected object: " + x);
170 }
171
172 adoptPet("bird"); // 输入的参数只能是“dog”“fish”“bird”之一
173 // adoptPet("cat"); //Error: 传入其他值会报错
174
175 // 上面的例子用switch-case写代码看起来更清晰简练一点
176 function adoptPetAgain(s: pet) : Animal {
177 switch (s) {
178 case "dog": return new Dog("小白");
179 case "bird": return new Bird("飞飞" );
180 case "fish": return new Fish("金金" );
181 default : return assertNever(s);
182 }
183 }
?
查看更多关于TypeScript入门笔记(三)的详细内容...
声明:本文来自网络,不代表【好得很程序员自学网】立场,转载请注明出处:http://www.haodehen.cn/did223474