# TypeScript类 本节我们共同完成上节中的作业:新建Teacher类。 ## 实体类 在团队项中,我们更愿意将与后台返回数据对应的类称为实体Entity类,表示此类与后台返回的数据格式一致。教师数据便是典型的由后台获取的数据,所以我们在`app`文件夹下新下`entity`文件夹: ```bash panjie@panjies-Mac-Pro app % pwd /Users/panjie/github/mengyunzhi/angular11-guild/first-app/src/app panjie@panjies-Mac-Pro app % tree -L 1 . ├── add ├── app-routing.module.ts ├── app.component.css ├── app.component.html ├── app.component.spec.ts ├── app.component.ts ├── app.module.ts ├── edit ├── entity 👈 ├── index └── login 5 directories, 6 files ``` 然后进入该文件夹,使用angular cli自动创建一个普通的teacher类: ```bash panjie@panjies-Mac-Pro entity % pwd /Users/panjie/github/mengyunzhi/angular11-guild/first-app/src/app/entity panjie@panjies-Mac-Pro entity % ng g class teacher CREATE src/app/entity/teacher.spec.ts (158 bytes) CREATE src/app/entity/teacher.ts (25 bytes) ``` Angualr cli将自动创建一个Teacher类及该类对应的测试文件。 ## class Teacher 此时我们便可以定义Teacher的属性了: ```typescript +++ b/first-app/src/app/entity/teacher.ts @@ -1,2 +1,11 @@ +/** + * 教师(用户) + */ export class Teacher { + id: number; + email: string; + name: string; + password: string; + sex: boolean; + username: string; } ``` 接着定义构造函数: ```typescript +++ b/first-app/src/app/entity/teacher.ts @@ -7,5 +7,14 @@ export class Teacher { name: string; password: string; sex: boolean; username: string; + + constructor(id: number, email: string, name: string, password: string, sex: boolean, username: string) { + this.id = id; + this.email = email; + this.name = name; + this.password = password; + this.sex = sex; + this.username = username; + } } ``` 接下来,我们便可以在Login的相关功能上使用该类型了。 ### 测试 ```typescript +++ b/first-app/src/app/entity/teacher.spec.ts @@ -2,6 +2,6 @@ import { Teacher } from './teacher'; describe('Teacher', () => { it('should create an instance', () => { - expect(new Teacher()).toBeTruthy(); + expect(new Teacher(1, 'email', 'name', 'password', true, 'username')).toBeTruthy(); }); }); ``` ## 规定类型 使用Teacher类重写登录组件: ```typescript +++ b/first-app/src/app/login/login.component.ts @@ -1,5 +1,6 @@ import {Component, EventEmitter, OnInit, Output} from '@angular/core'; import {HttpClient, HttpHeaders} from '@angular/common/http'; +import {Teacher} from '../entity/teacher'; @Component({ selector: 'app-login', @@ -7,13 +8,10 @@ import {HttpClient, HttpHeaders} from '@angular/common/http'; styleUrls: ['./login.component.css'] }) export class LoginComponent implements OnInit { - teacher = {} as { - username: string, - password: string - }; + teacher = {} as Teacher; @Output() - beLogin = new EventEmitter<{ username: string, name: string, email: string, sex: boolean }>(); + beLogin = new EventEmitter<Teacher>(); constructor(private httpClient: HttpClient) { } @@ -31,7 +29,7 @@ export class LoginComponent implements OnInit { httpHeaders = httpHeaders.append('Authorization', 'Basic ' + authToken); this.httpClient - .get<any>( + .get<Teacher>( 'http://angular.api.codedemo.club:81/teacher/login', {headers: httpHeaders}) .subscribe(teacher => this.beLogin.emit(teacher), ``` 重写Index 组件: ```typescript +++ b/first-app/src/app/index/index.component.ts @@ -1,4 +1,5 @@ import {Component, OnInit} from '@angular/core'; +import {Teacher} from '../entity/teacher'; @Component({ selector: 'app-index', @@ -15,7 +16,7 @@ export class IndexComponent implements OnInit { ngOnInit(): void { } - onLogin(teacher: { username: string, name: string, email: string, sex: boolean }): void { + onLogin(teacher: Teacher): void { console.log(new Date().toTimeString(), '子组件进行了数据弹射', teacher); this.login = true; } ``` 重写测试 ```typescript +++ b/first-app/src/app/login/login.component.spec.ts @@ -3,6 +3,7 @@ import {ComponentFixture, TestBed} from '@angular/core/testing'; import {LoginComponent} from './login.component'; import {FormsModule} from '@angular/forms'; import {HttpClientModule} from '@angular/common/http'; +import {Teacher} from '../entity/teacher'; describe('LoginComponent', () => { let component: LoginComponent; @@ -45,7 +46,7 @@ describe('LoginComponent', () => { it('onSubmit 用户登录', () => { // 启动自动变更检测 fixture.autoDetectChanges(); - component.teacher = {username: '张三', password: 'codedemo.club'}; + component.teacher = {username: '张三', password: 'codedemo.club'} as Teacher; component.onSubmit(); }); }); ``` ## 验证 是时候展示伟大的TypeScript以及`ng t`的伟大魅力了!在日常的开发工作中,我们常常因为不敢重构而放弃重构的想法,特别是一些弱类型的语言,肯定动一动某个属性的名称都会给我们带来恶梦。而有了TypeScript加之Angular为我们准备的`ng t`,我们再也不惧怕重构了。 此时我们可以使用`ng t`来验证本次重构是否成功。在使用`ng t`前,我们需要将所有的`fdescribe`、`fit`进行复原,以使得所有的测试文件均得到执行。又由于我们为每个组件都定义了对应的测试文件,所以若测试的代码全部成功的执行,则说明此次重构没有任何问题。 ![image-20210306111552816](https://img.kancloud.cn/f7/9a/f79ae60cfab69f46d087cefc2a896c2d_1070x608.png) ## 本节作业 我们在Teacher对应的测试文件中如下实例化Teacher: ```typescript +++ b/first-app/src/app/entity/teacher.spec.ts describe('Teacher', () => { it('should create an instance', () => { expect(new Teacher(1, 'email', 'name', 'password', true, 'username')).toBeTruthy(); }); }); ``` 而如果我们少填写一个参数,或是将对应参数的值输入undefined则会抛出异常: ![image-20210306112351640](https://img.kancloud.cn/b3/c5/b3c5c110229521ed14cd9ee57662ab95_3484x294.png) ![image-20210306111848252](https://img.kancloud.cn/13/be/13be5fab87a7965bee67ad16f457e4d6_2704x342.png) 请**尝试**通过自己的能力使Teacher的构造函数支持默认值,使以下代码正常执行: ```typescript describe('Teacher', () => { it('should create an instance', () => { expect(new Teacher()).toBeTruthy(); const id = 123; expect(new Teacher(id).toBeTruthy(); const email = 'zhangsan@codedemo.club'; expect(new Teacher(id, email).toBeTruthy(); }); }); ``` | 名称 | 地址 | 备注 | | --------------- | ------------------------------------------------------------ | ---- | | TypeScript 类 | [https://www.tslang.cn/docs/handbook/classes.html](https://www.tslang.cn/docs/handbook/classes.html) | | | TypeScript 类型 | [https://www.tslang.cn/docs/handbook/advanced-types.html](https://www.tslang.cn/docs/handbook/advanced-types.html) | | | 本节源码 | [https://github.com/mengyunzhi/angular11-guild/archive/step3.6.zip](https://github.com/mengyunzhi/angular11-guild/archive/step3.6.zip) | |