My question is how to use libraries like AmpersandJS or other libraries that parse configs to build your (class) objects (I'm not sure if this pattern has a name) with Typescript. For example Ampersand.JS uses a function (.extend) to build up a prototype based on your configuration:
// 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
I'm struggling how to use implement the above example with Typescript. With other libraries like Backbone, you can use the normal / straightforward Typescript approach:
MyModel extends Backbone.Model{}
However, with libraries like Ampersand.JS I cannot use:
Person extends AmpersandModel{}
as this would never execute the AmpersandModel's custom extend() code that builds the prototype based on the configuration passed to the extend() function.
I'm not sure what other libraries face this same problem, and what solutions they use. Any example of libraries that use the Ampersand's pattern could be of help.
Here's what I came up with- first I stubbed out the Ampersand.js module definition. I've never used Ampersand, so just going off their docs:
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;
Below is how you would use the above ampersand module definition to define your own interfaces, etc.
Due to limitations in what Typescript generics and inheritance can do you'll need to create two interfaces for every model type: one for it's properties and a second that combines the properties and the ampersand base model:
// 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!
[Here's a link to run the code in the typescript playground]
来源:https://stackoverflow.com/questions/25227309/how-to-use-typescript-with-libraries-like-ampersand-js-that-parse-configs-to-bui