Я использую Breeze + Typescript + Knockout для Spa, и я столкнулся со следующей проблемой: когда я создаю новый объект с EntityManager.createEntity, typescript не позволяет мне использовать наблюдаемые объекты, которые Breeze генерирует из метаданных. Машинопись "видит" только свойства entityAspect и entityType. Я использую определения типа DefininiteTyped. Любая помощь приветствуется!
Легкие сущности с машинописным текстом
Ответы (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);
});
}
Посмотрите мой ответ на типизированных объектах Breeze.js, в которых я взломал T4TS, чтобы плюнуть вне определений TS, поддерживающих Breeze.
Глядя на: 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;
}
и т.д. Поскольку интерфейсы являются открытыми, вы можете объявлять различные части определения интерфейса в нескольких файлах. Надеюсь это поможет.
Ниже приведена страница, которую вы можете разместить на своем сайте, чтобы сгенерировать определения интерфейса машинописного текста. Страница извлекает простые метаданные, затем выполняет итерацию по всем типам и выводит объявление интерфейса машинописного текста для каждого типа. Вывод этой страницы можно затем вставить в любой файл машинописного текста (* .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<';
html += getJSType(property.dataType.name);
html += '>; //' + 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<';
else
html += ': KnockoutObservableArray<';
html += property.entityType.shortName;
html += '>;' + 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>