Why does JHipster generate Interfaces for Angular model objects? - jhipster

Why does JHipster generate interfaces for each Angular model object?
e.g.
export interface IStudent {
id?: number;
studentIdentifier?: string;
firstName?: string;
lastName?: string;
}
export class Student implements IStudent {
constructor(
public id?: number,
public studentIdentifier?: string,
public firstName?: string,
public lastName?: string,
) {}
}

I cannot find the original discussion but in my understanding, this is because of the way how interfaces work in TypeScript, which is a little different than in Java. They not just describe how a class should look like by defining its method, but also which fields should be present. So you can define, how a JSON from somewhere should look like. Like a POJO. Or a POTO (plain old TypeScript object) :)
By example, you could do that:
let student: IStudent = { id: 123, studentIdentifier: '...',...}
and TS would check if your provided object satisfies the defined structure of student. When you get an object out from the API, you just map a JSON directly this way, so there is no class in between. From the other side, it's more handy to work with classes rather than interfaces, when building objects of IStudent directly. As it also satisfies IStudent, you can make just
let student: IStudent = new Student(123, '...', ..)
which is shorter.
You could rely also on my first snippet (this is how ionic does it, btw. Using interfaces as POJOs/POTOs). Using classes only in TS leads to a bad developer experience IMHO.
Hope that helps a little bit out

Related

pass only the fields on the interface typescript [duplicate]

When using typescript a declared interface could look like this:
interface MyInterface {
test: string;
}
And an implementation with extra property could be like this:
class MyTest implements MyInterface {
test: string;
newTest: string;
}
Example (here the variable 'reduced' still contain the property 'newTest'):
var test: MyTest = {test: "hello", newTest: "world"}
var reduced: MyInterface = test; // something clever is needed
Question
In a general way, how can you make the 'reduced' variable to only contain the properties declared in the 'MyInterface' interface.
Why
The problem occur when trying to use the 'reduced' variable with angular.toJson before sending it to a rest service - the toJson method transforms the newTest variable, even if it's not accessible on the instance during compile, and this makes the rest service not accept the json since it has properties that shouldn't be there.
It is not possible to do this. The reason being interface is a Typescript construct and the transpiled JS code is empty
//this code transpiles to empty!
interface MyInterface {
test: string;
}
Thus at runtime there is nothing to 'work with' - no properties exist to interrogate.
The answer by #jamesmoey explains a workaround to achieve the desired outcome.
A similar solution I use is simply to define the 'interface' as a class -
class MyInterface {
test: string = undefined;
}
Then you can use lodash to pick the properties from the 'interface' to inject into you object:
import _ from 'lodash'; //npm i lodash
const before = { test: "hello", newTest: "world"};
let reduced = new MyInterface();
_.assign(reduced , _.pick(before, _.keys(reduced)));
console.log('reduced', reduced)//contains only 'test' property
see JSFiddle
This is a pragmatic solution that has served me well without getting bogged down on semantics about whether it actually is an interface and/or naming conventions (e.g. IMyInterface or MyInterface) and allows you to mock and unit test
TS 2.1 has Object Spread and Rest, so it is possible now:
var my: MyTest = {test: "hello", newTest: "world"}
var { test, ...reduced } = my;
After that reduced will contain all properties except of "test".
Another possible approach:
As other answers have mentioned, you can't avoid doing something at runtime; TypeScript compiles to JavaScript, mostly by simply removing interface/type definitions, annotations, and assertions. The type system is erased, and your MyInterface is nowhere to be found in the runtime code that needs it.
So, you will need something like an array of keys you want to keep in your reduced object:
const myTestKeys = ["test"] as const;
By itself this is fragile, since if MyInterface is modified, your code might not notice. One possible way to make your code notice is to set up some type alias definitions that will cause a compiler error if myTestKeys doesn't match up with keyof MyInterface:
// the following line will error if myTestKeys has entries not in keyof MyInterface:
type ExtraTestKeysWarning<T extends never =
Exclude<typeof myTestKeys[number], keyof MyInterface>> = void;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Type 'UNION_OF_EXTRA_KEY_NAMES_HERE' does not satisfy the constraint 'never'
// the following line will error if myTestKeys is missing entries from keyof MyInterface:
type MissingTestKeysWarning<T extends never =
Exclude<keyof MyInterface, typeof myTestKeys[number]>> = void;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Type 'UNION_OF_MISSING_KEY_NAMES_HERE' does not satisfy the constraint 'never'
That's not very pretty, but if you change MyInterface, one or both of the above lines will give an error that hopefully is expressive enough that the developer can modify myTestKeys.
There are ways to make this more general, or possibly less intrusive, but almost no matter what you do, the best you can reasonably expect from TypeScript is that your code will give compiler warnings in the face of unexpected changes to an interface; not that your code will actually do different things at runtime.
Once you have the keys you care about you can write a pick() function that pulls just those properties out of an object:
function pick<T, K extends keyof T>(obj: T, ...keys: K[]): Pick<T, K> {
return keys.reduce((o, k) => (o[k] = obj[k], o), {} as Pick<T, K>);
}
And them we can use it on your test object to get reduced:
var test: MyTest = { test: "hello", newTest: "world" }
const reduced: MyInterface = pick(test, ...myTestKeys);
console.log(JSON.stringify(reduced)); // {"test": "hello"}
That works!
Playground link to code
Are you trying to only set/assign properties listed on the interface only? Functionality like that is not available in TypeScript but it is very simple to write a function to perform the behaviour you looking for.
interface IPerson {
name: string;
}
class Person implements IPerson {
name: string = '';
}
class Staff implements IPerson {
name: string = '';
position: string = '';
}
var jimStaff: Staff = {
name: 'Jim',
position: 'Programmer'
};
var jim: Person = new Person();
limitedAssign(jimStaff, jim);
console.log(jim);
function limitedAssign<T,S>(source: T, destination: S): void {
for (var prop in destination) {
if (source[prop] && destination.hasOwnProperty(prop)) {
destination[prop] = source[prop];
}
}
}
In your example newTest property won't be accessible thru the reduced variable, so that's the goal of using types. The typescript brings type checking, but it doesn't manipulates the object properties.
In a general way, how can you make the 'reduced' variable to only contain the properties declared in the 'MyInterface' interface.
Since TypeScript is structural this means that anything that contains the relevant information is Type Compatible and therefore assignable.
That said, TypeScript 1.6 will get a concept called freshness. This will make it easier to catch clear typos (note freshness only applies to object literals):
// ERROR : `newText` does not exist on `MyInterface`
var reduced: MyInterface = {test: "hello", newTest: "world"};
Easy example:
let all_animals = { cat: 'bob', dog: 'puka', fish: 'blup' };
const { cat, ...another_animals } = all_animals;
console.log(cat); // bob
One solution could be to use a class instead of an interface and use a factory method (a public static member function that returns a new object of it's type). The model is the only place where you know the allowed properties and it's the place where you don't forget to update them accidentaly on model changes.
class MyClass {
test: string;
public static from(myClass: MyClass): MyClass {
return {test: myClass.test};
}
}
Example:
class MyTest extends MyClass {
test: string;
newTest: string;
}
const myTest: MyTest = {test: 'foo', newTest: 'bar'};
const myClass: MyClass = MyClass.from(myTest);

NestJS class-validators on incoming requests using interface

I need to use an interface through class-validator to validate the incoming form for a specific field in the incoming request body.
The interface:
export enum Fields {
Full_Stack_Dev = 'full stack dev',
Frontend_Dev = 'frontend dev',
Backend_Dev = 'backend dev',
}
export interface Experience {
field: Fields;
years: number;
}
And here is the DTO Class:
#IsEnum(Languages)
languages: Languages[];
experience: Experience[]; // 👈 Not sure which decorator to use for interfaces
Okay after doing a lot of research, I found a workaound for this:
First of all, Interfaces CANNOT be used directly. Officially declared by class-validators issue here
This is what I did:
Changed the interface into a separate class and added validation on its properties
class ExperienceDto {
#IsEnum(Fields)
field: Fields;
#IsNumber()
years: number;
}
Then used this class as type to validate Array of Objects in the ACTUAL DTO CLASS (not the above one)
#ArrayNotEmpty()
#ArrayMinSize(1)
#ArrayMaxSize(3)
#ValidateNested({ each: true })
#Type(() => ExperienceDto) // imported from class-transformer package
experience: ExperienceDto[];

How can I set an entity type within a dto [NestJS]?

I don't even think I've got a proper question so I apologize greatly.
I am consuming a 3rd party API and to update or create records, one of the fields is the entity type.
For example, here is my CreateOrganizationDTO:
export class CreateOrganizationDto {
#ApiProperty({
description: "The entity type. Only 'organization' is allowed.",
example: "organization",
})
#IsNotEmpty()
readonly #type: string; <-- this
...
I'm not sure how to properly handle the # character. I've tried different versions of '#type' or ['#type']. Clearly, neither are correct. I'm also not sure how to send that data through my service. For example:
// MyService.ts
const {name, #type, active} = updateOrganizationDto;
organization.name = name;
organization.#type = #type; <-- not going to work :(
organization.active = active;
...
What is the proper way to "escape" this # throughout my application? Thank you for any suggestions!

The constructor for HSMWalletMixin in HLF 1.4 doesn't have the correct variables

I'm trying to connect to an HSM using fabric-network V1.4.17 looking at the HSMWalletMixin constructor there are no options to tell the class the library label and pin.
Instead all these variables can be found in the X509WalletMixin.
Here's the code in the class:
export interface WalletMixin {} // tslint:disable-line:no-empty-interface
export class X509WalletMixin implements WalletMixin {
public static createIdentity(mspId: string, certificate: string, privateKey: string): Identity;
constructor(library?: string, slot?: string, pin?: string, userType?: string);
}
export class HSMWalletMixin implements WalletMixin {
public static createIdentity(mspId: string, certificate: string): Identity;
constructor();
}
So I tried creating an HSM Wallet using the X509WalletMixin like below, but it created a regular wallet instead.
const hsmWalletMixin = new X509WalletMixin('/path/to/lib/libCryptoki2_64.so', 'slot', 'pin');
const wallet = new FileSystemWallet(walletPath, hsmWalletMixin);
So, How can create an HSM Wallet then? are there some environment variables like in this tutorial Testing for Hardware Security Module via PKCS#11?
Thanks
Looking at the source code the implementation is correct
https://github.com/hyperledger/fabric-sdk-node/blob/4ca22aa1a70f464c3a5b9c259542aa7fee651061/fabric-network/lib/impl/wallet/hsmwalletmixin.js#L40
What is not correct are the type definitions which is the code snippet you have posted.
It's only going to be an issue if you are using typescript in which case you will just have to not use the HSMWalletMixin type to ensure typescript doesn't try to do any validation.

Complex datatypes in HyperLedger Fabric

I read in out the documentation on HyperLedger. However, I cannot find any information on storing complex datatypes by that I mean if it is even possible. For instance lets say we have two objects: an author and a book. Is it possible to create a smartcontract that would look like this? (example in typescript) :
export class Book {
public ISBN: string;
public Title: string;
}
export class Author {
public firstName: string;
public lastName: string;
public publishedBooks: Array<Book>;
}
And if so how would querying would look like in such instance. On the other hand if it is not possible how would one model such data relations in HyperLedger.
Yes you can do this.
Implement it in the smart contract and use Hyperledger directives to query the ledger.
For example in Go you can use shim PutState and GetState to determine an entity given an ID.
If you implement a DB like CouchDB you can even do more complex and rich queries on your database.
[EDIT1] Answer improvement with example:
This is how I improved this in my Go Chaincode
type V struct {
Attribute string `json:"Attribute"`
Function string `json:"Function"`
Value string `json:"Value"`
}
type AV struct {
Vs []V `json:"Vs"`
CFs map[string]string `json:"CFs"`
}
As you can see, I am using V struct for an array of Vs.
This make my dataset more complex and this is inside the chaincode.
[EDIT 2] Answer improvement with query and put:
Adding a new entity is very easy. My examples are always in GoLang.
Send a JSON to the chaincode (thanks to the SDK) and next unmarshal it:
var newEntity Entity
json.Unmarshal([]byte(args[0]), &newEntity)
Now use the PutState function to put the new entity given his ID (in my case contained in the JSON file, id field):
entityAsBytes, _ := json.Marshal(newEntity)
err := APIstub.PutState(newEntity.Id, entityAsBytes)
And here you are done. If you now want to query the ledger retrieving that id, you can do:
entityAsByte, err := APIstub.GetState(id)
return shim.Success(entityAsByte)

Resources