Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- # Typescript class transformer
- Typescript nam prinása mnoho výhod. Jedna z nich je EcmaScript6 class. Je to elegantné riešenie pre implementáciu modelov v MVC frameworkoch. Pre bežnú komunikáciu medzi aplikáciou a serverom sa často používa JSON format, ktory je skratkou pre JavaScript Object Notation. Tu nastáva problem, JSON je len dátová štruktúra, nie instancia triedy. Čiže ked na backende zavoláme JSON.stringify tak sa instancia triedy zmení na retazec zakódovaného JSON objektu a všetky naše metódy a typy sa stratia. Ako teda naše typy a metódy obnovíme ked znova zavoláme JSON.parse ? Použijeme node modul class-transformer. Funguje ako na frontende tak aj na backende. Tento modul obsahuje sadu dekorátorov a funkcií, ktoré sa o to postarajú.
- ## Ako na to
- Samozrejme si package nainstalujeme cez náś obľúbený package manager.
- ```yarn add class-transformer``` alebo ```npm install --save class-transformer```
- Vytvoríme si jednoduchú triedu na ktorej si to odskúšame.
- ```typescript
- class Human{
- firstname: string;
- surname: string;
- public fullname() {
- return this.firstname + ' ' + this.surname;
- }
- }
- let human = Human();
- human.firstname = 'John';
- human.surname = 'Doe';
- ```
- Teraz spravíme z instancie reťazec vo formáte JSON.
- ```typescript
- let json = JSON.stringify(human);
- console.log(json) // -> "{"firstname": "John", "surname": "Doe"}"
- ```
- Ked použijeme JSON.parse tak nedostaneme instanciu ale iba javascript objekt a naša snaha o zavolanie metódy nam vráti error
- ```typescript
- let obj = JSON.parse(json);
- console.log(obj.fullname()) -> // TypeError : obj.fullname is not a function
- ```
- Preto použijeme class-transformer ktory znovu vytvorí instanciu triedy Human.
- ```typescript
- import {plainToClass} from 'class-transformer';
- ...
- let obj = JSON.parse(json);
- let human = plainToClass(Human, obj);
- console.log(human.fullname()) // -> "John Doe"
- ```
- Čo sa ale stane ked máme do seba vnorené 2 instancie tried? Použijeme dekorátor ```@Type(() => class)```. Plaintoclass funkcia funguje rekurzívne a zo všetkých dekorovaných vlastností vytvorí instancie.
- ```typescript
- import {Type} from 'class-transformer';
- class Dog {
- name: string = void 0;
- public bark() {
- return this.name + ': Bork!';
- }
- }
- class Human{
- firstname: string;
- surname: string;
- @Type(() => Dog)
- bestfriend: Dog;
- public fullname() {
- return this.firstname + ' ' + this.surname;
- }
- }
- let human = JSON.parse('{"firstname": "John", "secondname": "Doe", "bestFriend": {"name": "Jack the dog"}}');
- human = plainToClass(Human, human);
- console.log(human.bestFriend.bark()) // -> "Jack the dog: Bork!"
- ```
- V databáze máme uložený zoznam užívateľov a kazdý obsahuje email, meno a heslo. Chceme zoznam užívateľov zobraziť v tabulke niekde na frontende a nechceme samozrejme posielat heslo.
- ```typescript
- import {Exclude} from 'class-transformer';
- class User{
- name: string;
- email: string;
- @Exclude({toPlainOnly: true})
- password: string;
- }
- ```
- Teraz ked vieme využiť silu dekorátorov a class-transformeru pouzijeme ďalší modul, class-validator (Je to modul od rovnakeho autora), ktorý bude validovat vstup od užívateľa. Napríklad pri registrácii.
- ```typescript
- class User {
- // nechceme aby user posielal id takže ho vyradíme
- @Exclude()
- _id: string = void 0;
- // použijeme 2 dekorátory class-validatoru ktoré skontrolujú či vlastnost nie je prázdna a je to string
- // pre správne fungovanie class-validatoru musíme nastaviť defaultnu hodnotu vlastnosti na "void 0", pretože
- // typescript transpiler ho nezahrnie v transpilovanej triede a validátor ho nerozpozná
- @IsNotEmpty()
- @IsString()
- firstname: string = void 0;
- @IsNotEmpty()
- @IsString()
- surname: string = void 0;
- // ďalši dekorátor class-validatoru skontroluje či je vlastnosť email
- @IsNotEmpty()
- @IsEmail()
- email: string = void 0;
- // samozrejme nechceme posielať heslo na frontend ale chceme aby ho užívateľ poslal na backend
- @Exclude({toPlainOnly: true})
- @IsNotEmpty()
- password: string = void 0;
- // id chceme poslat na frontend a zmeniť jeho kľúč z "_id" na id
- @Expose({name: 'id'})
- get id() {
- return this._id;
- }
- public async genPassword() {}
- }
- ```
- ```typescript
- // funkcia používa async/await
- public async register(data) {
- // vytvorí instanciu z javascript objektu
- let user = plainToClass(User, data);
- // skontroluje či užívateľ vyplnil všetko správne (funckia je asynchrónna čize očakávame promise)
- let errors = await validate(user);
- // ak pri validácii nastal problém funkcia vyhodé error
- if(errors.length > 0){
- throw new Error(RegisterErrorStatus.WRONG_DATA);
- }
- // skontroluje či užívateľ existuje v databázi
- if (await this.userExists(user)) {
- throw new Error(RegisterErrorStatus.USER_EXISTS);
- }
- // vygeneruje heslo, použije na to metódu triedy User
- await user.genPassword();
- // vloží do databáze
- this.db.insert(User, user);
- }
- ```
- S použitím class-transformeru, class-validatoru a async/await je zápis funkcie velmi elegantný a pocit z písania backendu v typescripte príjemný.
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement