How to use type check Loopback / Fireloop PersistedModel - loopback

I'm using Fireloop with Loopback 3 and wanting to know how best to create typesafe hooks and remote methods using type checked PersistedModel and Validatable methods. I'd like to change the type of the constructor from ...
constructor(public model: any) { }
to ...
constructor(public model: SomeType) { }
I'd like to make PersistedModel calls like
this.model.count().then((n) => ...);
OR Validatable calls like:
model.validatesLengthOf('code', {
min: 6, max: 12, message: { min: 'too short', max: 'too long'}
});
The Fireloop examples like the one below only use any as type of this.model.
The firestarter model samples and Fireloop documentation were also of no use here.
I know that there is a type called ModelConstructor declared in the fireloop source tree under core/index.d.ts. This interface looks correct because it implements all the PersistedModel and Validatable methods but where is it published in npmjs? Is it already part of the Fireloop server SDK or do I need to npm install it? No idea.
import { Model } from '#mean-expert/model';
/**
* #module Account
* #description
* Write a useful Account Model description.
* Register hooks and remote methods within the
* Model Decorator
**/
#Model({
hooks: {
beforeSave: { name: 'before save', type: 'operation' }
},
remotes: {
myRemote: {
returns: { arg: 'result', type: 'array' },
http: { path: '/my-remote', verb: 'get' }
}
}
})
class Account {
// LoopBack model instance is injected in constructor
constructor(public model: any) { }
// Example Operation Hook
beforeSave(ctx: any, next: Function): void {
console.log('Account: Before Save', ctx.instance);
next();
}
// Example Remote Method
myRemote(next: Function): void {
this.model.find(next);
}
}
module.exports = Account;
Finially, I've also attempted to use the Loopback 3 Typescript definitions but hit more problems as the PersistedModel methods here are all declared as static so fail type checks and return Promise<T> | void. The later means you’re forced to type cast the result back to just Promise<T> so it seems like the type def authors have never actually used them. Is this a bug or am I missing something? Can't find any working examples to prove otherwise.
This is the server side API pain. Client side REST API for Fireloop is also undocumented (lots of example for Real-time API) but none for the REST api it's also supposed to include (just mentioned once in one issue). Would be nice to find it can all be type checked by Typescript.

I found that ModelConstructor validation methods were missing arguments like { message: 'my error message' } and methods like exists() returned Promise<any> instead of Promise<boolean>.
The type definitions in Loopback 3 Type definitions were more complete but were unusable unless fixed as described above.
In the end I used ..
# Used modified type defs from https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/loopback/index.d.ts
import { Validatable } from '../types/validatable';
# Fixed static methods and return types.
import { PersistedModel } from '../types/loopback';
constructor(public MyModel: Validatable | PersistedModel) {
let Model = MyModel as Validatable;
Model.validatesLengthOf('code', {
min: 6,
max: 80,
message: { min: 'too short', max: 'too long' } });
Model.validatesFormatOf('email',
{ with: this.reEmail,
message: 'invalid email address',
allowNull: false });
Model.validatesInclusionOf('role', {
in: RoleNames,
message: 'is not valid'
});
}
And in later methods ..
let Model = this.MyModel as PersistedModel;
// knows that isFound is boolean
Model.exists(code).then(isFound => { ... });

Related

Cannot read property 'type' of undefined ember and firebase

I am trying to retrieve data from my firestore using ember.js and emberfire.
i have a simple movie database. All that is in it right now is 1 document but for some reason when i try and retrieve the data, i keep getting "Cannot read property 'type' of undefined"! i understand that this is a JSONAPI issue but nothing seems to fix it.
My Route:
import Route from '#ember/routing/route';
export default class MovieRoute extends Route {
async model() {
this.store.findAll('movies').then(function(movie) {
console.log(movie);
});
}
}
My Model:
import Model, { attr } from '#ember-data/model';
export default class MoviesModel extends Model {
#attr('string') title;
}
Now it was my understanding that the default JSONAPISerializer is the default one but i tried adding a serializer anyway and my error changes to: Assertion Failed: normalizeResponse must return a valid JSON API document.
My adapter:
import FirestoreAdapter from 'emberfire/adapters/firestore';
export default FirestoreAdapter.extend({
// Uncomment the following lines to enable offline persistence and multi-tab support
// enablePersistence: true,
// persistenceSettings: { synchronizeTabs: true },
});
My Serializer:
import JSONAPISerializer from '#ember-data/serializer/json-api';
export default class ApplicationSerializer extends JSONAPISerializer {}
it is also my understanding that the way the JSON is to be accepted is:
{
data {
type: 'movies',
id: 1,
attributes {
title: 'ghostbusters'
}
}
}
so i also created a new document in the firestore, following this same format. Still no luck.
Can anyone point me in the right direction as to how to get the correct data returning from the firestore?
**edited --
error message:

Typescript - Get uninitialized properties after compilation

I am currently writing a wrapper around socket.io. Comming from a very object-oriented background, I want to implement the concept of Models in my framework/wrapper.
If you happen to know socket.io you might know that you get the data that is associated with an event as a parameter, now I have implemented a custom routing system where the handler of the route gets the data in an express.js like request object.
The idea is to have model classes that look something like this:
class XRequestModel
#v.String({ message: 'The username must be a string!' })
public userName: string;
}
And the route event might look something like this:
#RouteConfig({ route: '/something', model: XRequestModel })
class XEvent extends Route {
public on(req: Request<XRequestModel>, res: Response) {
// Handle Event
}
}
And to complete the example here is how the request object might look like:
class Request<T> {
public data: T;
}
Now generics in typescript are very limited since the type information is removed after compilation, I can not use the generic Request parameter ( which is the type of the model ) to get metadata from the model - Metadata, in this case, is the validation decorator. To overcome this issue I give a reference of the Model class to the RouteConfig of the RouteEvent, which is internally used and would allow me to create instances of the model, get the properties and so on...
The idea here is to give the handler of a route, a request object with pre-validated, typesafe data.
The thing holding me back from this, is the fact that unused properties, get removed after compilation by typescript, So I cannot get the metadata of the model. Initializing the class-property would solve this:
class XRequestModel
#v.String({ message: 'The username must be a string!' })
public userName: string = '';
}
But I think this makes for some very verbose syntax, and I dont want to force the user of this wrapper to init all the model properties.
An implementation side-note:
The user of the framework has to register the classes to a 'main' class and from there I can get the Route-class via decorator reflection.
When I try to get the properties of the model without initialized properties - First model example.
// Here the route.config.model refers to the model from the RouteConfig
Object.getOwnPropertyNames(new route.config.model());
>>> []
Here is what I get with initialized properties:
Object.getOwnPropertyNames(new route.config.model());
>>> [ 'userName' ]
Here a link to the GitHub repository: https://github.com/FetzenRndy/SRocket
Note that models are not implemented in this repo yet.
Basically, my question is: How can I get the properties of a class that has uninitialized properties after compilation.
The problem is that if no initialization happens, no code is emitted for the fields, so at runtime the field does not exist on the object until a value is assigned to it.
The simplest solution would be to initialize all fields even if you do so with just null :
class XRequestModel {
public userName: string = null;
public name: string = null;
}
var keys = Object.getOwnPropertyNames(new XRequestModel())
console.log(keys); // [ 'userName', 'name' ]
If this is not a workable solution for you, you can create a decorator that adds to a static field on the class and the walk up the prototype chain to get all fields:
function Prop(): PropertyDecorator {
return (target: Object, propertyKey: string): void => {
let props: string[]
if (target.hasOwnProperty("__props__")) {
props = (target as any)["__props__"];
} else {
props = (target as any)["__props__"] = [];
}
props.push(propertyKey);
};
}
class XRequestModelBase {
#Prop()
public baseName: string;
}
class XRequestModel extends XRequestModelBase {
#Prop()
public userName: string;
#Prop()
public name: string;
}
function getAllProps(cls: new (...args: any[]) => any) : string[] {
let result: string[] = [];
let prototype = cls.prototype;
while(prototype != null) {
let props: string[] = prototype["__props__"];
if(props){
result.push(...props);
}
prototype = Object.getPrototypeOf(prototype);
}
return result;
}
var keys = getAllProps(XRequestModel);
console.log(keys);

howto: optional (nested) class property?

I have a class which I want to have some optional nested properties.
class Input {
stuff {
first_name?: string; // optional
};
however it seems that isn't legal typescript. ; expected
Next is to pull stuff out into an interface
interface IFrom {
id: any;
first_name?: string;
};
class Input {
from:IFrom;
however when i put these in the same file I get
tsPublic property 'from' of exported class has or is using private name 'IFrom'.
I can't make public interface
'public' modifier cannot appear on a module element.
What I've ended up doing is putting the interface in yet another file, but this is getting to be astronaut engineering where every struct and property needs to be in its own file...
Am I missing something about how best to do this?
I want the first_name property to be public but part of a struct.
Want it to be optional.
Prefer fewer individual files.
Thanks!
however it seems that isn't legal typescript. ; expected
The syntax for inline types is incorrect. You are missing a :. The following works fine:
class Input {
stuff: {
first_name?: string; // optional
};
}
That answers the question. But since you tried more stuff:
Public property 'from' of exported class has or is using private name 'IFrom'.
You probably have export class ... that means that you need to do export interface too to export any interface that the class uses.
You should use the keyword export with interfaces and classes, not public.
Here is an example:
module ModuleA {
export interface IFrom {
id: any;
first_name?: string;
}
}
module ModuleB {
export class Input {
from:ModuleA.IFrom;
}
}
var input = new ModuleB.Input();
input.from = {id: 123, first_name: 'Bob'};
alert(input.from.first_name); // Bob

How to properly bind current object context in ES6 using babelify

I'm trying to bind current instance to the class method, please note ES6 syntax.
class SomeClass {
search() => { ... }
}
Which is 100% legit code, however, babelify doesn't want to compile it
SyntaxError: /Users/vladmiller/Projects/test/test/client/test/app/pages/Search.react.js: Unexpected token (50:26) while parsing file: /Users/vladmiller/Projects/test/test/client/test/app/pages/Search.react.js\
Instead, now I have to bind context in class constructor
class SomeClass {
constructor() {
this.search = this.search.bind(this)
}
search() { ... }
}
Which is quite annoying and boring.
UPD: It turns out that this is invalid ES6 syntax; therefore the question is follows. What is the best way to bind instance context to a class method?
UPD2: By default context should be attached, however, the issue with React http://jsbin.com/citafaradu/2/edit?js,console,output
This code is not valid ES2015. Prototype methods are defined like this:
class SomeClass {
search() { /* ... */ }
}

Typescript: Cannot export a module that is a generic interface and contains other generic interfaces

I'm trying to write a CommonJS declaration file for Bluebird, a promise library that directly exports a generic Promise class. However, the library also exports several other generic classes as static members (PromiseInspection), and it seems like its impossible to model this with typescript.
Edit: Usage example, to illustrate how the module's exported class works:
import Promise = require('bluebird');
var promise:Promise<number> = Promise.cast(5);
var x:Promise.PromiseInspection<number> = promise.inspect();
I tried several strategies - simplified examples follow:
1. The obvious way
declare module "bluebird" {
class PromiseInspection<T> {
// ...
}
class Promise<T> {
PromiseInspection: typeof PromiseInspection; // error
constructor<T>();
inspect():PromiseInspection<T>; // error
static cast<U>(value:U):Promise<U>;
// ...
}
export = Promise;
}
Fails with the error unable to use private type PromiseInspection as a public property
2. Using a static interface
declare module "bluebird2" {
interface PromiseInspection<T> {
// ...
}
interface Promise<T> {
constructor<T>();
inspect():PromiseInspection<T>;
}
interface PromiseStatic {
new<T>();
PromiseInspection:typeof PromiseInspection;
cast<U>(value:U):Promise<U>; // error
}
export = PromiseStatic;
}
Also fails similarly, but this time the private type is Promise
3. Trying to directly export a constructor function from the module
declare module "bluebird3" {
export interface PromiseInspection<T> {
// ...
}
export interface Promise<T> {
constructor<T>();
inspect():PromiseInspection<T>;
}
export new<T>(); // syntax error
export function cast<U>(value:U):Promise<U>;
}
This almost works, except of course its impossible to a constructor function that way.
4. The namespace polluting way (Works, with downsides)
interface PromiseInspection<T> {
// ...
}
interface Promise<T> {
constructor<T>();
inspect():PromiseInspection<T>;
}
declare module "bluebird4" {
interface PromiseStatic {
new<T>():Promise<T>;
PromiseInspection: typeof PromiseInspection;
cast<U>(value:U):Promise<U>;
}
export = PromiseStatic;
}
Works, but it pollutes the global namespace with both Promise and PromiseInspection. This might be okay but I'd rather avoid it as in CommonJS its usually considered unacceptable.
5. With declaration merging (gets me 90% of the way...)
declare module "bluebird5" {
module Promise {
export interface PromiseInspection<T> {
value(): T;
// ...
}
export
function cast<U>(value: U): Promise<U> ;
}
class Promise<T> {
new <T> (): Promise <T> ;
inspect(): Promise.PromiseInspection <T> ;
}
export = Promise;
}
Almost there - except that now I'm not allowed to replace class Promise<T> with interface Promise<T>, making Promise<T> unextendable. If I try to do it, the following code:
import Promise = require('bluebird');
var x = new Promise<number>();
x.inspect().value().toExponential();
fails with the error "Invalid 'new' expression"
Link to the actual, work-in-progress bluebird.d.ts - this one currently pollutes the global namespace (uses solution 4)
Is there a better way to do this, or did I hit a language limitation?
Anders Hejlsberg posted an answer on CodePlex, so I'm going to add it here. The declaration merging solution was close - but I also needed a "var" declaration to declare the static interface as it is the only one that can accept a constructor function.
declare module "bluebird" {
module Promise {
export interface PromiseInspection<T> {
value(): T;
}
}
interface Promise<T> {
inspect(): Promise.PromiseInspection <T> ;
}
var Promise: {
new<U>(): Promise<U>;
cast<U>(value: U): Promise<U> ;
}
export = Promise;
}
So basically:
interface members in the module declaration (as long as they declare just types i.e. non-physical)
instance members in the main interface
static function members, the constructor and other "physical" members in the var declaration.
Also, his comment:
Writing it this way you have a separate declaration for each of the three meanings of the identifier Promise: As a namespace (a module containing only types), as a type (that happens to be generic), and as a value.
Looking at your code I noticed you were missing a few export statements. The code below compiles - would it suit?
declare module bluebird {
export class PromiseInspection<T> {
// ...
}
export class Promise<T> {
constructor<T>();
inspect():PromiseInspection<T>;
static all<T>(promises:Promise<T>[]):Promise<T[]>;
}
}
declare module "bluebird" {
export = bluebird;
}
Though I generally favour using interfaces when defining typings as in #2:
declare module bluebird {
export interface PromiseInspection<T> {
// ...
}
export interface Promise<T> {
constructor<T>();
inspect():PromiseInspection<T>;
}
export interface PromiseStatic {
new<T>();
all<T>(promises:Promise<T>[]):Promise<T[]>;
}
}
declare module "bluebird" {
export = bluebird;
}
Failing that have you tried using another promises library as the basis for your typings? You could do worse than look at https://github.com/borisyankov/DefinitelyTyped/blob/master/q/Q.d.ts
Roughly speaking they look a little like this:
declare function Q<T>(promise: Q.IPromise<T>): Q.Promise<T>;
declare function Q<T>(promise: JQueryPromise<T>): Q.Promise<T>;
declare function Q<T>(value: T): Q.Promise<T>;
declare module Q {
//… functions etc in here
}
declare module "q" {
export = Q;
}