如何导入自定义EventEmitter并避免TS错误:2339?

时间:2019-11-10 20:34:01

标签: typescript

我目前正在使用在普通JavaScript上制作的样板之上的TypeScript配置项目。我的问题出现在preLaunchTask中的TS编译期间。我无法在本地导入的自定义EventEmitter上访问'report'属性。这是TS中的以下错误:

error TS2339: Property 'report' does not exist on type 'EventEmitter'.

下面是 testing.ts 文件:

'use strict';

import cors from 'cors';
import fs from 'fs';
import runner from '../../test-runner';
import express from 'express';

export default function (app: express.Application) {

  app.route('/_api/server.js')
    .get(function (req: express.Request, res: express.Response, next: Function) {
      console.log('requested');
      fs.readFile(__dirname + '/server.js', function (err, data) {
        if (err) return next(err);
        res.send(data.toString());
      });
    });
  app.route('/_api/routes/api.js')
    .get(function (req: express.Request, res: express.Response, next: Function) {
      console.log('requested');
      fs.readFile(__dirname + '/routes/api.js', function (err, data) {
        if (err) return next(err);
        res.type('txt').send(data.toString());
      });
    });
  app.route('/_api/controllers/convertHandler.js')
    .get(function (req: express.Request, res: express.Response, next: Function) {
      console.log('requested');
      fs.readFile(__dirname + '/controllers/convertHandler.js', function (err, data) {
        if (err) return next(err);
        res.type('txt').send(data.toString());
      });
    });

  var error;
  app.get('/_api/get-tests', cors(), function (req: express.Request, res: express.Response, next) {
    console.log(error);
    if (!error && process.env.NODE_ENV === 'test') return next();
    res.json({ status: 'unavailable' });
  },
    function (req: express.Request, res: express.Response, next: Function) {
      if (!runner.report) return next();
      res.json(testFilter(runner.report, req.query.type, req.query.n));
    },
    function (req: express.Request, res: express.Response) {
      runner.on('done', function (report) {
        process.nextTick(() => res.json(testFilter(runner.report, req.query.type, req.query.n)));
      });
    });
  app.get('/_api/app-info', function (req: express.Request, res: express.Response) {
    var hs = Object.keys(res.header)
      .filter(h => !h.match(/^access-control-\w+/));
    var hObj = {};
    hs.forEach(h => { hObj[h] = res.header[h] });
    delete res.header['strict-transport-security'];
    res.json({ headers: hObj });
  });

};

function testFilter(tests, type, n) {
  var out;
  switch (type) {
    case 'unit':
      out = tests.filter(t => t.context.match('Unit Tests'));
      break;
    case 'functional':
      out = tests.filter(t => t.context.match('Functional Tests') && !t.title.match('#example'));
      break;
    default:
      out = tests;
  }
  if (n !== undefined) {
    return out[n] || out;
  }
  return out;
}

这是我正在尝试导入的测试运行器:

var analyser = require('./assertion-analyser');
var EventEmitter = require('events').EventEmitter;

var Mocha = require('mocha'),
    fs = require('fs'),
    path = require('path');

var mocha = new Mocha();
var testDir = './tests'


// Add each .js file to the mocha instance
fs.readdirSync(testDir).filter((file) => {
    // Only keep the .js files
    return file.substr(-3) === '.js';

}).forEach((file) => {
    mocha.addFile(
        path.join(testDir, file)
    );
});

var emitter = new EventEmitter();  
emitter.run = () => {

  let tests = [];
  var context = "";
  var separator = ' -> ';
  // Run the tests.
  try {
  var runner = mocha.ui('tdd').run()
    .on('test end', (test) => {
        // remove comments
        var body = test.body.replace(/\/\/.*\n|\/\*.*\*\//g, '');
        // collapse spaces
        body = body.replace(/\s+/g,' ');
        var obj = {
          title: test.title,
          context: context.slice(0, -separator.length),
          state: test.state,
          body: body,
          assertions: analyser(body)
        };
        tests.push(obj);
    })
    .on('end', () => {
        emitter.report = tests;
        emitter.emit('done', tests)
    })
    .on('suite', (s) => {
      context += (s.title + separator);

    })
    .on('suite end', (s) => {
      context = context.slice(0, -(s.title.length + separator.length))
    })
  } catch(e) {
    throw(e);
  }
};

module.exports = emitter;

还有我的 tsconfig.json 文件:

{
    "compilerOptions": {
        "target": "esnext",
        "moduleResolution": "node",
        "allowJs": true,
        "noEmit": true,
        "isolatedModules": true,
        "esModuleInterop": true,
        "noImplicitReturns": true,
        "lib": [
            "dom",
            "es6"
        ],
        "outDir": "public",
        "sourceMap": true
    },
    "include": [
        "src",
    ]
}

我试图尽我最大的努力来缩小问题的范围,但我对为什么进出口似乎没有对彼此的回应感到困惑。最近,我一直在解决许多重新配置错误,所以我的大脑可能对此太想了。请随时告诉我是否还有其他可用的代码。

1 个答案:

答案 0 :(得分:0)

我调整了我的'preLaunchTask'以使其完全符合我的TS编译器脚本名称-这不是问题。我收到的TypeScript错误是我的测试运行器上的'report'属性为空,这是由于测试运行器文件中的语法较旧,这是由于原始测试运行器作者直接将属性分配给EventEmitter的一个实例。为了使TS编译器满意,我改为将测试运行程序代码调整为基于类的设置,在构造函数中添加“报告”,从而避免了原始测试运行程序的“ void”或“()=> void”返回值。 / p>

test-runner2.js

import analyser from '../../assertion-analyser';
import { EventEmitter } from 'events';

import Mocha from 'mocha';
import fs from 'fs';
import path from 'path';
import { connect } from 'http2';

const mocha = new Mocha();
const testDir = './tests';

// Add each .js file to the mocha instance.
fs.readdirSync(testDir).filter(file => {
    return file.substr(-3) === '.js';
}).forEach(file => {
    mocha.addFile(
        path.join(testDir, file)
    );
});

class TestEmitter extends EventEmitter {
    constructor() {
        this.report = []
    }

    run = () => {
        // Run the tests...
        let tests = [];
        let context = '';
        let separator = ' ~> ';

        try {
            const runner = mocha.ui('tdd').run()
                .on('test end', test => {
                    // remove comments
                    let body = test.body.replace(/\/\/.*\n|\/\*.*\\/g, '');
                    // collapse spaces
                    body = body.replace(/\s+/g, '');
                    const obj = {
                        title: test.title,
                        context: context.slice(0, -separator.length),
                        state: test.state,
                        body: body,
                        assertions: analyser(body)
                    };
                    tests.push(obj);
                })
                .on('end', () => {
                    emitter.report = tests;
                    emitter.emit('done', tests)
                })
                .on('suite', (s) => {
                  context += (s.title + separator);

                })
                .on('suite end', (s) => {
                  context = context.slice(0, -(s.title.length + separator.length))
                });
        } catch(err) {
            throw(err);
        }
    }
}

export default TestEmitter;

tsconfig.json:

{
    "compilerOptions": {
        "target": "es5",
        "moduleResolution": "node",
        "allowJs": true,
        "noEmit": true,
        "isolatedModules": true,
        "esModuleInterop": true,
        "noImplicitReturns": true,
        "lib": [
            "dom",
            "es6"
        ],
        "outDir": "public",
        "sourceMap": true
    },
    "include": [
        "src",
    ]
}

希望这可以帮助其他尝试将TS添加到普通JS样板中的人。我也发布了我的配置文件。使用class节点extends默认类的EventEmitter