Как использовать 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!

[Вот ссылка для запуска кода на площадке для машинописи]

Другие вопросы по тегам