Как использовать Typescript с библиотеками, такими как Ampersand.js, которые анализируют конфигурации для создания прототипов
Мой вопрос заключается в том, как использовать библиотеки, такие как AmpersandJS или другие библиотеки, которые анализируют конфиги для создания ваших (классов) объектов (я не уверен, что у этого шаблона есть имя) с Typescript. Например, Ampersand.JS использует функцию (.extend) для создания прототипа на основе вашей конфигурации:
// This object contains the configuration that Ampersand uses to build my model.
var config = {
props: {
firstName: 'string',
lastName: 'string'
}
};
// Create a Person model with getters, setters, validation etc.
var Person = AmpersandModel.extend(config);
// A basic usage to create an instance of a Person object
var myPerson = new Person({firstName:"John", lastName:"Doe"});
myPerson.firstName = "NewJohn"; // runs the first name setter build by ampersand
Я изо всех сил, как использовать реализовать приведенный выше пример с Typescript. С другими библиотеками, такими как Backbone, вы можете использовать обычный / простой подход Typescript:
MyModel extends Backbone.Model{}
Однако с такими библиотеками, как Ampersand.JS, я не могу использовать:
Person extends AmpersandModel{}
так как это никогда не выполнит пользовательский код extend() AmpersandModel, который создает прототип на основе конфигурации, переданной функции extended ().
Я не уверен, какие другие библиотеки сталкиваются с этой же проблемой, и какие решения они используют. Любой пример библиотек, которые используют шаблон Амперсанда, может помочь.
1 ответ
Вот что я придумал - сначала я заглушил определение модуля Ampersand.js. Я никогда не использовал Ampersand, так что просто схожу с их документов:
declare module ampersand {
interface AmpersandState {
// todo...
}
interface AmpersandCollection {
// todo...
}
interface ModelExtendOptions {
parse?: boolean;
parent?: AmpersandState;
collection?: AmpersandCollection;
}
interface ModelSaveOptions {
patch?: boolean;
}
interface AmpersandModel<TProps> {
save: (attrs?: TProps, options?: ModelSaveOptions) => void;
// todo: fetch, destroy, sync, etc...
}
interface AmpersandModelConstructor<TProps, TModel extends AmpersandModel<any>> {
new (attrs: TProps, options?: ModelExtendOptions): TModel;
}
interface ExtendOptions {
props?: {};
session?: {};
derived?: {};
}
interface AmpersandModelStatic {
extend: <TProps, TModel extends AmpersandModel<any>>(options: ExtendOptions) => AmpersandModelConstructor<TProps, TModel>;
}
}
declare var AmpersandModel: ampersand.AmpersandModelStatic;
Ниже описано, как вы могли бы использовать приведенное выше определение модуля амперсанда для определения собственных интерфейсов и т. Д.
Из-за ограничений в возможностях обобщений и наследования Typescript вам потребуется создать два интерфейса для каждого типа модели: один для его свойств и второй, который объединяет свойства и базовую модель амперсанда:
// interface for person properties...
interface PersonProps {
firstName: string;
lastName: string;
}
// interface to tie everything together...
interface PersonModel extends PersonProps, ampersand.AmpersandModel<PersonProps> {
}
// use AmpersandModel's extend method...
var Person = AmpersandModel.extend<PersonProps, PersonModel>({ props: { firstName: 'string', lastName: 'string' } });
// at this point you now have full intellisense/type checking for the constructor and properties.
var me = new Person({ firstName: 'Jeremy', lastName: 'Danyow' });
me.firstName = 'Ron'; // yes!
me.eyeColor = 'Brown'; // compile error!