简体   繁体   中英

TypeError: Ajv is not a constructor

I have this class where I try to instantiate Ajv with the new keyword and I get this error:

TypeError: Ajv is not a constructor

Code:

import * as Ajv from "ajv";

    export class ValidateJsonService {
        validateJson(json, schema) {
            console.log(Ajv);
            let ajv = new Ajv({ allErrors: true });
            if (!ajv.validate(schema, json)) {
                throw new Error("JSON does not conform to schema: " + ajv.errorsText())
            }
        }
    }

The console log:

在此处输入图片说明

This code used to be working and it is how Ajv is used. From the Ajv docs:

The fastest validation call:

var Ajv = require('ajv');
var ajv = new Ajv(); // options can be passed, e.g. {allErrors: true}
var validate = ajv.compile(schema);
var valid = validate(data);
if (!valid) console.log(validate.errors);

How come I'm getting this error?

See the bottom of this for how I import the Ajv library - systemjs.config.js:

(function (global) {
    System.config({
        paths: {
            // paths serve as alias
            'npm:': 'lib/js/'
        },
        // map tells the System loader where to look for things
        map: {
            app: 'app', 
            // angular bundles
            '@angular/core': 'npm:@angular/core/bundles/core.umd.js',
            '@angular/common': 'npm:@angular/common/bundles/common.umd.js',
            '@angular/compiler': 'npm:@angular/compiler/bundles/compiler.umd.js',
            '@angular/platform-browser': 'npm:@angular/platform-browser/bundles/platform-browser.umd.js',
            '@angular/platform-browser-dynamic': 'npm:@angular/platform-browser-dynamic/bundles/platform-browser-dynamic.umd.js',
            '@angular/http': 'npm:@angular/http/bundles/http.umd.js',
            '@angular/router': 'npm:@angular/router/bundles/router.umd.js',
            '@angular/forms': 'npm:@angular/forms/bundles/forms.umd.js',
            // other libraries
            'rxjs': 'npm:rxjs',
            'angular2-in-memory-web-api': 'npm:angular2-in-memory-web-api',
            'angular2-google-maps/core': 'npm:angular2-google-maps/core/core.umd.js',
            'ajv': 'npm:ajv/dist/ajv.min.js',
            'primeng': 'npm:primeng'

I saw that Ajv has a default function so I changed my code to this:

let ajv = new Ajv.default({ allErrors: true });

Not 100% sure what is going on there but it works.

Old question and old answer, but since I think the accepted answer isn't ideal and also leaves unanswered questions, I'm still adding my $.02:

What's causing this is that ajv uses export default or export = syntax, and you're using import * as which imports an object with all exported members from the ajv module, where the default export is a property called default .

The most reasonable way to import the default constructor function is to use:

import Ajv from 'ajv';
const ajv = new Ajv(...);

rather than

import * as Ajv from 'ajv';
const ajv = new Ajv.default(...); // Ajv is an object containing _all_ exports from the ajv module

If you absolutely feel that you must use import * , then this would at least be cleaner, so that Ajv rather than Ajv.default is the constructor function:

import * as AjvModule from 'ajv';
const {default: Ajv} = AjvModule;

If using require rather than import to access exported members from a module that uses export default , it will behave like import * as Ajv , ie, you will get an object with a default property in it.

So the following are equivalent:

// Pre-ES6 require
const Ajv = require('ajv').default;
const ajv = new Ajv(...);

// Import default
import Ajv from 'ajv';
const ajv = new Ajv(...);

// Import entire module and use default property
import * as Ajv from 'ajv';
const ajv = new Ajv.default(...); // just ugly!

// Import entire module as AjvModule and assign constructor function to Ajv
import * as AjvModule from 'ajv';
const {default: Ajv} = AjvModule;
const ajv = new Ajv(...);

If you do need to import the default export and additional exported members, you can do that without resorting to import * as :

import Ajv, {EnumParams} from 'ajv';
const ajv = new Ajv(...);

Personally I think the accepted answer is somewhat flawed because if you're only interested in importing the ajv constructor function, it makes sense to assign it to the Ajv variable rather than the object that contains the constructor function as a property called default - and then create classes with new Ajv.default syntax - that just looks strange.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM