Breeze.js typed entities
Asked Answered
P

6

5

Is there a way to create typed entities using Breeze in the same way that JaySvcUtil works for JayData? Does this include Typescript support - also is there general Typescript support within the Breeze framework?

Phthisic answered 11/12, 2012 at 9:28 Comment(1)
As of v 0.84.4, breeze provides full TypeScript support via a 'breeze.d.ts' file available on the breeze website within the breeze zips found here.Plio
P
4

We do have plans to do more with TypeScript, but haven't yet committed to a specific time frame. (Boris's work, mentioned in John's post, is certainly a great start).

UPDATE: As of v 0.84.4, Breeze provides full TypeScript support.

As far as automatically generating design time Javascript classes for each entity; we have had several internal discussions on this, but are really waiting to see what the community votes for. We will almost certainly get around to this at some point, but your votes on the
UserVoice can definitely expedite the process.

Plio answered 11/12, 2012 at 19:56 Comment(0)
S
6

This gist contains a modified version of T4TS that contains some initial support for generating "design time Javascript classes for each entity" with support for Breeze.

https://gist.github.com/alexdresko/5393155

So far, it suits my needs. I'm pretty sure you need to have the DefinitelyTyped Breeze definition in your solution for this to work properly.

Maybe this is something that could be added to T4TS permanently? Maybe it's something for the Breeze team to consider? Or maybe it's just stupid and doesn't really work for anyone but me. :)

In my dataservice, I can do something like:

    createOrganization() : T4TS.Organization {
        return <T4TS.Organization>this.manager.createEntity("Organization");
    }

Then, in my VM, all of this code is nicely typesafe..

    organizationSubmit() {
        this.editingOrganization(false);
        var newOrganization = this.dataservice.createOrganization();

        newOrganization.Name(this.organizationNameInput());
        if (newOrganization.entityAspect.validateEntity()) {
            this.extendOrganization(newOrganization);
            this.organizations.push(newOrganization);
            this.dataservice.saveChanges();
            this.organizationNameInput("");
        } else {
            this.handleItemErrors(newOrganization);

        }
    };

I don't really know where to go with this from here. I tried forking T4TS, but didn't have time to figure out his build system. Hence the gist. Opinions are certainly welcome.

Sateen answered 16/4, 2013 at 3:42 Comment(4)
I have started discussing Breeze in T4TS in this issue (started by @alex-dresko): github.com/cskeppstedt/t4ts/issues/14Guanaco
Very nice, is this still the best way to go or is there another version that has been updated?Casto
I replied to your question on the github issue.Sateen
Thanks hopefully @Guanaco can chime in with an update to his projects :)Casto
P
4

We do have plans to do more with TypeScript, but haven't yet committed to a specific time frame. (Boris's work, mentioned in John's post, is certainly a great start).

UPDATE: As of v 0.84.4, Breeze provides full TypeScript support.

As far as automatically generating design time Javascript classes for each entity; we have had several internal discussions on this, but are really waiting to see what the community votes for. We will almost certainly get around to this at some point, but your votes on the
UserVoice can definitely expedite the process.

Plio answered 11/12, 2012 at 19:56 Comment(0)
P
2

Below is a page you can drop in your site to generate typescript interface definitions. The page fetches the breeze metadata then iterates through all of the types and outputs a typescript interface declaration for each type. The output of this page can then be pasted in any typescript file (*.ts) or typescript definition file (*.d.ts). Enclose the results in a module declaration if you want to namespace the interfaces: declare module northwind { ... paste interfaces here... }.

Before using the page you'll need to make one edit: change the entity manager's controller url from "api/northwind" to whatever your breeze controller's url is.

The generated interfaces have a dependency on the Knockout.js typescript definitions which you can grab here: https://github.com/borisyankov/DefinitelyTyped/tree/master/knockout/

Using the northwind example from learn.breezejs.com, the output of this definitions generator page would be something like this:

export interface Employee extends breeze.Entity {
    FirstName: KnockoutObservable<string>;
    LastName: KnockoutObservable<string>;
}

you could then execute a query using breeze and cast the results to an array of employees like this:

var manager = new breeze.EntityManager('api/northwind');

var query = new breeze.EntityQuery()
    .from("Employees");

manager.executeQuery(query).then(data => {
    // ***cast the results to a strongly typed array of Employee***
    var employees = <Employee[]>data.results;
}).fail(e => {
    alert(e);  
});

below is the definitions generator page- add a new html file to your project named "definitions.html", run the project and navigate to the page.

<html>
<head>
    <title>Typescript Definition Generator</title>
    <style>
        code {
            white-space: pre;
        }
    </style>
    <script src="//code.jquery.com/jquery-2.1.0.min.js"></script>
    <script src="//ajax.aspnetcdn.com/ajax/knockout/knockout-3.0.0.js"></script>
    <script src="//cdnjs.cloudflare.com/ajax/libs/q.js/1.0.0/q.min.js"></script>
    <script src="//cdnjs.cloudflare.com/ajax/libs/breezejs/1.4.4/breeze.min.js"></script>
    <script type="text/javascript">
        $(document).ready(function () {
            var entityManager = new breeze.EntityManager('api/northwind');
            entityManager.fetchMetadata()
                .then(function () {
                    var html = '',
                        types = entityManager.metadataStore.getEntityTypes(),
                        type,
                        i,
                        j,
                        property,
                        crlf = String.fromCharCode(13),
                        code = document.createElement('code'),
                        script = document.createElement('script');

                    function getJSType(metadataType) {
                        if (/(Int64)|(Int32)|(Int16)|(Byte)|(Decimal)|(Double)|(Single)|(number)/.test(metadataType))
                            return 'number';
                        else if (/(DateTime)|(DateTimeOffset)|(Time)|(Date)/.test(metadataType))
                            return 'Date';
                        else if (/(Boolean)/i.test(metadataType))
                            return 'boolean';
                        return 'string';
                    }

                    for (i = 0; i < types.length; i++) {
                        // type declaration
                        var type = types[i];
                        html += 'export interface ' + type.shortName;

                        // base type
                        html += ' extends ';
                        if (type.hasOwnProperty('baseEntityType')) {
                            html += type.baseEntityType.shortName;
                        } else {
                            html += 'breeze.Entity';
                        }
                        html += ' {' + crlf;

                        // data properties
                        for (j = 0; j < type.dataProperties.length; j++) {
                            property = type.dataProperties[j];
                            if (type.baseEntityType && type.baseEntityType.dataProperties.filter(function (p) { return p.name === property.name; }).length > 0)
                                continue;
                            html += '    ' + property.name;
                            //if (property.isNullable)
                            //    html += '?';
                            html += ': KnockoutObservable&lt;';
                            html += getJSType(property.dataType.name);
                            html += '&gt;; //' + property.dataType.name + crlf;
                        }

                        // navigation properties
                        for (j = 0; j < type.navigationProperties.length; j++) {
                            property = type.navigationProperties[j];
                            if (type.baseEntityType && type.baseEntityType.navigationProperties.filter(function (p) { return p.name === property.name; }).length > 0)
                                continue;
                            html += '    ' + property.name;
                            //if (property.isNullable)
                            //    html += '?';
                            if (property.isScalar)
                                html += ': KnockoutObservable&lt;';
                            else
                                html += ': KnockoutObservableArray&lt;';
                            html += property.entityType.shortName;
                            html += '&gt;;' + crlf;
                        }

                        html += '}' + crlf + crlf;
                    }

                    code.innerHTML = html;

                    $(code).addClass('prettyprint');

                    document.body.appendChild(code);

                    script.setAttribute('src', '//google-code-prettify.googlecode.com/svn/loader/run_prettify.js');
                    document.body.appendChild(script);
                })
                .fail(function (reason) {
                    alert(reason);
                });
        });
    </script>
</head>
<body>
</body>
</html>
Piscatelli answered 23/3, 2014 at 13:53 Comment(5)
Pretty awesome. I'm new to TypeScript. My collections are coming out looking like, for example, this... "ControlValues: ControlValue;". Why isn't the type a generic container of item type ControlValue?Cakewalk
@IanWarburton- good call. I've updated the answer to generate the correct property types: KnockoutObservable<T> and KnockoutObservableArray<T>. Thanks for pointing that out.Piscatelli
And thank you for your great answer. Have you any idea how this could be incorporated in to Visual Studio's build pipeline?Cakewalk
oh actually, I still don't think the generator is correct. Now its always creating a collection. I think the generator needs to discern whether the navigation property is a reference to a single item or to a collection.Cakewalk
good catch- I've updated the logic to check the navigation property's isScalar flag. I don't know of a way to incorporate this into the build process. @Jay-Traband might know of another way to do this.Piscatelli
B
2

For breeze TypeScript defiintions, use NuGet package breeze.TypeScript.DefinitelyTyped. To create definitions for your entities, you can use TypeLITE. It will create a .d.ts file with interfaces like this:

declare module MyProject.Models {
interface Customer {
  Id: number;
  AccountNumber: string;
  ...

While these interfaces fully describe your entities, they don't extend breeze.Entity. To play nicely with the Breeze API type definitions, derive your own interfaces from these, like this:

import Models = MyProject.Models;
interface Customer extends Models.Customer, breeze.Entity { }
...

This still involves some manual coding, but at least it's only per type, not per property.

Bandaid answered 5/8, 2014 at 12:57 Comment(0)
C
1

Regarding Typescript, it is definitely on our radar. At a minimum we will create a TypeScript 'declare' file that will allow better intellisense when using Breeze.

You can vote it up over on UserVoice.

Until then you might want to use Boris Yankov's DefinitelyTyped which supports Breeze.

Casto answered 11/12, 2012 at 19:19 Comment(2)
Thanks. So are there plans for devel time typed entities? I'm coming from a .net background and trying to decide between jaydata and breeze for a new mobile project. Breeze kinda feels more familiar but without typed client side "classes" and intellisense it just sounds like a real chore to get stuff done!Phthisic
I'm biased but I have not found lack of intellisense for the entities to be the huge obstacle that I expected it to be. I want it to be sure. But there are so many more urgent annoyances in JS :) Evaluate JayData by all means. I'd like to know if this is the decisive difference.Sitin
V
0

my two cents...

I have been using the definatelytyped definition file for breeze and it seems to work well.

It is fairly straightforward to create a T4 script to generate .d.ts files for all the entities in an .edmx and then you get the intellisense you desire. If Ward likes, I could post a sample T4 script somewhere.

Venturesome answered 9/1, 2013 at 3:12 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.