Легкие сущности с машинописным текстом

Я использую Breeze + Typescript + Knockout для Spa, и я столкнулся со следующей проблемой: когда я создаю новый объект с EntityManager.createEntity, typescript не позволяет мне использовать наблюдаемые объекты, которые Breeze генерирует из метаданных. Машинопись "видит" только свойства entityAspect и entityType. Я использую определения типа DefininiteTyped. Любая помощь приветствуется!


person frenchfaso    schedule 21.03.2013    source источник


Ответы (4)


Вы можете создать интерфейс для своего типа, который расширяет breeze.Entity:

/// <reference path="breeze.d.ts" />
module model {
    export interface ResponsesItem extends breeze.Entity {
        ContentTypeID: string;
        Title: string;
        Description: string;
        EventDate: any;
        /* etc. */
    }
}

Затем вы можете преобразовать свои объекты в этот интерфейс всякий раз, когда вам нужно работать с ними типизированным способом, например, результат запроса при загрузке с сервера:

     private loadResponses(): void {
         this.dataservice.ListResponses()
            .then((data: { results: breeze.Entity[]; query: breeze.EntityQuery; XHR: XMLHttpRequest; }) => {
                var results: model.ResponsesItem[] = <model.ResponsesItem[]>data.results;
                // Do something with typed results array here.
         }).fail((error) => {
            this.handleDataError(error);
         });
      }
person Jude Fisher    schedule 22.03.2013
comment
Спасибо JcFx, звучит хорошо! Попробую это сделать и доложу :-) PS: Что делать, если у меня есть несколько моделей, отправленных разными запросами Breeze? - person frenchfaso; 23.03.2013
comment
Я не совсем уверен, о чем вы спрашиваете, но да - у меня есть отдельный метод в моем сервисе данных на стороне клиента для каждого типа, поэтому я знаю, чего ожидаю от конкретного вызова, и могу соответствующим образом выполнять приведение. Имейте в виду, что свойством интерфейса может быть другой интерфейс, поэтому у вас может быть структурированная типизированная модель. Также ознакомьтесь с полезным шаблоном T4 от Christoffer для создания интерфейсов из ваших серверных классов: github.com/cskeppstedt/t4ts - person Jude Fisher; 23.03.2013

Посмотрите мой ответ на типизированных объектах Breeze.js, в которых я взломал T4TS, чтобы плюнуть вне определений TS, поддерживающих Breeze.

person Alex Dresko    schedule 16.04.2013

Глядя на: https://github.com/borisyankov/DefinitiTyped/blob/master/knockout/knockout.d.ts

Функции, которые вы видите на ko (например, наблюдаемые и т. Д.), Являются функциями, определенными в интерфейсе KnockoutStatic из-за этой строки:

declare var ko: KnockoutStatic;

Вот фрагмент этого интерфейса:

interface KnockoutStatic {
    utils: KnockoutUtils;
    memoization: KnockoutMemoization;
    bindingHandlers: KnockoutBindingHandlers;
    virtualElements: KnockoutVirtualElements;
    extenders: KnockoutExtenders;

    applyBindings(viewModel: any, rootNode?: any): void;
    applyBindingsToDescendants(viewModel: any, rootNode: any): void;
    applyBindingsToNode(node: Element, options: any, viewModel: any): void;

    subscribable: KnockoutSubscribableStatic;
    observable: KnockoutObservableStatic;
    computed: KnockoutComputedStatic;
    observableArray: KnockoutObservableArrayStatic;
    .....

Поэтому, если вам нужны новые функции на ko, вам необходимо определить новые функции для интерфейса KnockoutStatic, например:

interface KnockoutStatic {
    yourFunc: KnockoutObservableStatic;
}

и т.д. Поскольку интерфейсы являются открытыми, вы можете объявлять различные части определения интерфейса в нескольких файлах. Надеюсь это поможет.

person basarat    schedule 22.03.2013
comment
Хай, спасибо за ответ. Я не уверен, что это решит мою проблему, заключающуюся в том, что TypeScript не может уловить динамическую природу Breeze Entities. - person frenchfaso; 23.03.2013

Ниже приведена страница, которую вы можете разместить на своем сайте, чтобы сгенерировать определения интерфейса машинописного текста. Страница извлекает простые метаданные, затем выполняет итерацию по всем типам и выводит объявление интерфейса машинописного текста для каждого типа. Вывод этой страницы можно затем вставить в любой файл машинописного текста (* .ts) или файл определения машинописного текста (* .d.ts). Включите результаты в объявление модуля, если вы хотите разместить интерфейсы в пространстве имен: declare module northwind { ... paste interfaces here... }.

Перед использованием страницы вам нужно сделать одно редактирование: изменить URL-адрес контроллера диспетчера сущностей с «api / northwind» на любой URL-адрес вашего контроллера Breeze.

Сгенерированные интерфейсы зависят от определений машинописного текста Knockout.js, которые вы можете найти здесь: https://github.com/borisyankov/DefinentyTyped/tree/master/knockout/

Используя пример северного ветра из learn.breezejs.com, вывод этой страницы генератора определений будет примерно таким:

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

затем вы можете выполнить запрос с помощью breeze и передать результаты массиву сотрудников следующим образом:

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);  
});

Ниже приведена страница генератора определений - добавьте в проект новый файл HTML с именем «definitions.html», запустите проект и перейдите на страницу.

<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>
person Jeremy Danyow    schedule 24.03.2014