Импортировать Victor.js в TypeScript? - программирование

Импортировать Victor.js в TypeScript?

Я пытаюсь использовать библиотеку victor.js в проекте TypeScript (3.0.1), и у меня реальная душевная боль при попытке импортировать и использовать ее. Я установил его из npm, а также набрал его (victor @types/victor). Я попытался импортировать его множеством способов, но не могу заставить его импортировать вместе с разрешением типов в моей IDE.

Я пробовал это:

import { Victor} from 'victor';  
import * as v from 'victor'; 

(На этот модуль можно ссылаться только при импорте/экспорте ECMAScript, включив флаг allowSyntheticDefaultImports и указав ссылку на его экспорт по умолчанию)

import Victor = require('victor');  

(работает, но не совместимо при нацеливании на модули ecmascript)

const Victor = require("victor");  

(Импортирует правильно, и я могу создавать объекты, но ни один из типов не присутствует)

Я уверен, что кто-то там сталкивался с подобной ситуацией раньше. Если это помогает, то в вершине index.js победителя есть строка:

exports = module.exports = Victor;
4b9b3361

Ответ 1

Вкратце

Вы пытаетесь использовать victor как если бы это был модуль es6, но это не так. Я вижу два варианта:

  1. Позвольте tsc преобразовать ваши модули в формат, подобный commonjs, и в этом случае tsc предоставит необходимую tsc логику между victor и вашим кодом

  2. Или вам нужно загрузить свое приложение через загрузчик модулей, который обеспечивает клей.

Детальное объяснение

Когда я запускаю последнюю tsc с указанным импортом, я получаю сообщение об ошибке:

На этот модуль можно ссылаться только при импорте/экспорте ECMAScript, включив флаг esModuleInterop и указав ссылку на его экспорт по умолчанию.

Когда я включаю esModuleInterop, то он работает просто отлично. Вот тестовый код, который я использовал:

import Victor from "victor";

const foo = new Victor(1, 2);
console.log(foo.y);

И tsconfig.json:

{
  "compilerOptions": {
    "esModuleInterop": true
  }
}

Проблема возникает из-за того, что при import Victor from "victor" вы запрашиваете значение, которое будет экспортировано с помощью оператора export default..., который является синтаксисом, предоставляемым модулями es6. Однако victor экспортирует все, что соответствует export default... Так что-то должно преодолеть разрыв. С тем, что я показал выше, когда вы компилируете, tsc выдает следующее:

"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
exports.__esModule = true;
var victor_1 = __importDefault(require("victor"));
var foo = new victor_1["default"](1, 2);
console.log(foo.y);

Обратите внимание на вспомогательную функцию __importDefault. Он используется всякий раз, когда код TS хочет получить доступ к тому, что модуль экспортирует как export default... Что он делает, так это проверяет, претендует ли модуль на модуль es6. Модуль es6, который хочет экспортировать значение по умолчанию, уже правильно структурирован, поэтому ничего не нужно делать, если модуль является модулем es6. Если модуль не является модулем es6, то помощник создает своего рода поддельный модуль, экспортируемым по умолчанию значением которого является значение исходного модуля.

Здесь есть важное предостережение, поскольку вы упоминаете "нацеливание на модули ecmascript". Если вы используете, это tsconfig.json:

{
  "compilerOptions": {
    "esModuleInterop": true,
    "module": "es6"
  }
}

Тогда испускаемый код:

import Victor from "victor";
var foo = new Victor(1, 2);
console.log(foo.y);

Обратите внимание, что больше нет вспомогательной функции. Это зависит от загрузчика модулей, который будет загружать модули для вашего приложения, чтобы обеспечить ту же логику, что и __importDefault. Если я переименую файл, чтобы иметь расширение mjs и запустить:

$ node --experimental-modules test.mjs

Я получаю этот вывод:

(node:18394) ExperimentalWarning: The ESM module loader is experimental.
2

При использовании Node с поддержкой экспериментального модуля он обеспечивает ту же функциональность, что и __importDefault.


Когда вы просто используете allowSyntheticDefaultImports без esModuleInterop вы сообщаете компилятору, что в вашем наборе инструментов есть что-то, что выполнит работу __importDefault. Таким образом, компилятор не предоставляет помощника. Это позволяет продолжить компиляцию, но позже вы будете ответственны за использование загрузчика модулей, который будет выполнять ту же работу, что и __importDefault.

Ответ 2

Я чувствую вашу душевную боль, в которой я потратил много времени на отладку различных ошибок в том, как писать файлы определений машинописи для существующих модулей javascript, и, наконец, достиг того, что я думал, было последним препятствием, когда я застрял на той же ошибке:

На этот модуль можно ссылаться только при импорте/экспорте ECMAScript, включив флаг allowSyntheticDefaultImports и указав ссылку на экспорт по умолчанию.

Рассматриваемый javascript здесь:

module.exports = class AthenaExpress { ...more code.. }

tsconfig.json для компиляции/"Рабочая версия" 1:

{
  "compilerOptions": {
    "outDir": "dist/",
    "sourceMap": true,
    "noImplicitAny": true,
    "module": "commonjs",
    "target": "es6",
    "jsx": "react"
  },
  "baseUrl": "./src",
  "include": [
    "**/*"
  ],
  "exclude": [
    "node_modules"
  ]
}

"Рабочая версия" файла d.ts с некоторыми отличиями при импорте 2:

declare module 'athena-express' {
    import * as aws from "aws-sdk";
    interface ConnectionConfigInterface {
        aws: typeof aws,
        s3: string,
        getStats: boolean
    }
    interface QueryResultsInterface {
        Items: any[],
        DataScannedInMB: number,
        QueryCostInUSD: number,
        EngineExecutionTimeInMillis: number,
        Count: number,
    }

    interface QueryInterface {
        sql: string,
        db: string,
    }

    type QueryResult = QueryResultsInterface

    interface AthenaExpressInterface {
        new: (config: ConnectionConfigInterface) => any,
        query: (query: QueryInterface) => QueryResult,
    }

    class AthenaExpress {
        new: (config: ConnectionConfigInterface) => any;
        constructor(config: ConnectionConfigInterface);
        query: (query: QueryInterface) => QueryResult;
    }
}

Версия файла d.ts, получившая такую же ошибку, даже когда был включен esModuleInterop, я также безрезультатно esModuleInterop с module и target. С разницей в утверждении импорта 3:

import * as aws from "aws-sdk";
interface ConnectionConfigInterface {
    aws: typeof aws,
    s3: string,
    getStats: boolean
}
interface QueryResultsInterface {
    Items: any[],
    DataScannedInMB: number,
    QueryCostInUSD: number,
    EngineExecutionTimeInMillis: number,
    Count: number,
}

interface QueryInterface {
    sql: string,
    db: string,
}

type QueryResult = QueryResultsInterface

interface AthenaExpressInterface {
    new: (config: ConnectionConfigInterface) => any,
    query: (query: QueryInterface) => QueryResult,
}

declare class AthenaExpress {
    new: (config: ConnectionConfigInterface) => any;
    constructor(config: ConnectionConfigInterface);
    query: (query: QueryInterface) => QueryResult;
}

export = AthenaExpress

заметки:

Расположение файла определения и файл, который я пытался заставить работать с определением:

 tree src/backend/js
    src/backend/js
        ├── athena-express.d.ts
        └── helloworld.ts
  1. "Рабочая версия" означает, что tsc похоже, компилируется без жалоб
  2. В helloworld.ts import {AthenaExpress} from "athena-express";
  3. В helloworld.ts import * as AthenaExpress from "./athena-express";

Ответ 3

Я вижу, что уже были отличные ответы, но хотел бы добавить этот более короткий ответ.

Сообщение об ошибке: This module can only be referenced with ECMAScript imports/exports by turning on the 'esModuleInterop' flag and referencing its default export.ts(2497)

У меня была проблема с импортом при переходе с es5 на es6 (и с javascript на машинописный текст) при преобразовании моего собственного файла javascript в машинописный текст.

Импортировать как import * as File from "./MyFile" в OtherFile.ts.

В файле MyFile.ts у меня был export = {funcName} в конце.

Решение состояло в том, чтобы удалить = как этот export {funcName} из файла MyFile.ts.

(Надеюсь, это поможет кому-то, впервые пытаясь найти ответ на ошибку/проблему)