Search code examples
javascripttypesloopbackjs

How do you access loopback model property types? (model.definition.properties.type)


How can you access the model property types from within a model extension file (model.js)?

If I try to access MODEL.definition.properties I'm able to see the following for a given property:

{ type: [Function: String],
[1]   required: false,
[1]   description: 'deal stage' }

Why is the type listed as [Function: String] instead of just "String" or something of the sort?

If I run typeof(property.type) it returns "function", but if I run property.type() it returns an empty string.


Solution

  • Disclaimer: I am a co-author and a current maintainer of LoopBack.

    TL;DR

    Use the following expression to obtain the property type as a string name. Please note it works only for a subset of possible property definitions (see later), most notably it does not support arrays.

    const type = typeof property.type === 'string' 
      ? property.type
      : property.type.modelName || property.type.name;
    

    The long version

    LoopBack allows the property type to be defined in several ways:

    1. As a string name, e.g. {type: 'string', description: 'deal stage'}. You can use a model name as the type too, e.g. {type: 'Customer'}.
    2. As a type constructor, e.g. {type: String, description: 'deal stage'}. You can use a model constructor as the type too, e.g. {type: Customer}.
    3. As a definition of an anonymous model, e.g. {type: {street: String, city: String, country: String}
    4. As an array type. The type of array items can be specified using any of the three ways described above (as a string name, a type constructor or an anonymous model definition).

    Read more in our documentation: LoopBack types

    To better understand how to process different kinds of property definitions, you can check the code in loopback-swagger that is converting a LoopBack model schema into Swagger Schema (which is similar to JSON Schema):

    The function getLdlTypeName takes a property definition (slightly normalized by buildFromLoopBackType) on the input and returns the property type as a string name.

    exports.getLdlTypeName = function(ldlType) {
      // Value "array" is a shortcut for `['any']`
      if (ldlType === 'array') {
        return ['any'];
      }
    
      if (typeof ldlType === 'string') {
        var arrayMatch = ldlType.match(/^\[(.*)\]$/);
        return arrayMatch ? [arrayMatch[1]] : ldlType;
      }
    
      if (typeof ldlType === 'function') {
        return ldlType.modelName || ldlType.name;
      }
    
      if (Array.isArray(ldlType)) {
        return ldlType;
      }
    
      if (typeof ldlType === 'object') {
        // Anonymous objects, they are allowed e.g. in accepts/returns definitions
        // TODO(bajtos) Build a named schema for this anonymous object
        return 'object';
      }
    
      if (ldlType === undefined) {
        return 'any';
      }
    
      var msg = g.f('Warning: unknown LDL type %j, using "{{any}}" instead', ldlType);
      console.error(msg);
      return 'any';
    };