#typescript #express
#typescript #экспресс
Вопрос:
Это то, что работает с require
. Вместо этого мы хотим, чтобы оно использовало import
.
import { Request, Response, Application } from 'express';
// TODO Figure out how NOT to use require here.
const express = require('express');
var app: Application = express();
app.get('/', function (req: Request, res: Response) {
res.send('Hello World')
});
app.listen(3000);
Что мы пробовали
В нашем tsconfig.json есть "esModuleInterop": true
.
Попытка # 1
import express from 'express';
Это выдает эту ошибку:
«node_modules/@types/express /index»‘ не имеет файла export.ts по умолчанию
Попытка # 2
import * as express from 'express';
var app = express();
Это выдает другую ошибку:
Не удается вызвать выражение, у типа которого отсутствует сигнатура вызова. Тип ‘typeof e’ не имеет совместимых подписей вызовов.ts(2349) index.ts(1, 1): Тип создается при этом импорте. Импорт в стиле пространства имен не может быть вызван или сконструирован и вызовет сбой во время выполнения. Рассмотрите возможность использования импорта по умолчанию или импорта require здесь вместо этого.
Комментарии:
1. Я могу рассказать вам, почему попытка # 2 не сработала: вы запросили объект пространства имен модуля, затем попытались запустить его как функцию.
2. Похоже,
@types/express
отсутствует тот факт, что Express предоставляет экспорт по умолчанию, который является функцией. (Я только что дважды проверил, что это так, и этоimport express from "express";
правильно извлекает его в коде JavaScript с--experimental-modules
включенным.) Так что определенно дело в типах (как следует из ошибки). Заглядывая вnode_modules/@types/express/index.d.ts
, я вижу, что он, по крайней мере, пытается определить экспорт для экспресс-функции: «Создает экспресс-приложение. Функция express() — это функция верхнего уровня, экспортируемая модулем express.»3. @T.J.Crowder Принудительное приведение к функции работает:
const app = (express as unknown as Function)();
. Хотя это, безусловно, уродливый взлом.4. (Говоря о взломах:
import * as mno from 'express'; const express = mno.default as unknown as Function;
) Но реальное решение (с которым, к сожалению, я не могу помочь) заключается в сортировке типов в@types/express/index.d.ts
и / или их использовании TypeScript.5. Сортировка типов была бы полезным запросом на извлечение. Я могу добавить это к моему списку дел «может быть, когда-нибудь».
Ответ №1:
TypeScript имеет специальный синтаксис импорта для работы с модулями, которые экспортируют функции или некоторые другие пользовательские объекты целиком (не как экспорт по умолчанию):
import { Request, Response, Application } from 'express';
import express = require('express');
var app: Application = express();
app.get('/', function (req: Request, res: Response) {
res.send('Hello World')
});
app.listen(3000);
В качестве альтернативы вы можете использовать параметры компилятора TypeScript для изменения импортируемого модуля, чтобы у них был экспорт по умолчанию:
// tsconfig.json
{
"compilerOptions": {
"allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
"esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
}
}
и импортировать, используя этот импорт по умолчанию:
import express from 'express'
var app = express();
Комментарии:
1. Это полезно. Однако в нашем случае мы ориентируемся на модули ECMAScript и видим это сообщение об ошибке: «Назначение импорта не может быть использовано при таргетинге на модули ECMAScript …»
2. @ShaunLuttin Боюсь, что использование bare
require()
— лучший способ для вас. В качестве альтернативы, если вы используете webpack или babel, вы могли бы предварительно обработать модульexpress
, чтобы «включить» его в экспорт по умолчанию, но это, вероятно, слишком хлопотно и может привести к путанице в типах.3. @ShaunLuttin Вы уверены, что хотите настроить таргетинг на модули ECMAScript в своем серверном коде? Узел использует commonjs. Вероятно, вы объединяете все модули перед их запуском с node, так что это не имеет значения, но опять же, зачем использовать какой-то определенный тип модулей, отличных от собственных модулей nodejs? Зачем вставлять круглый колышек в квадратное отверстие, если в итоге вы собираетесь залить все это бетоном?
4. Это потрясающий момент в использовании
commonjs
на стороне сервера. Я пошел дальше и попробовал это. Поскольку мы используемbabel/plugin-transform-typescript
для переноса вместо использованияtsc
, возникает новая ошибка, поскольку система сборки babel не позволяетimport =
работать. Мы могли бы установить--allowSyntheticDefaultImports
, но это (раньше) имело некоторые крайние случаи, которых мы хотим избежать.5. Комбинация использования
commonjs
и настройкиallowSyntheticDefaultImports
, иesModuleInterop
того иtrue
другого, похоже, работает.
Ответ №2:
Для того, чтобы иметь возможность импортировать express в обычный js-проект с:
import express from 'express';
Это тоже можно сделать:
- Задайте пару ключ-значение:
"type": "module",
в вашем package.json
файле
- Запустите ваше приложение с помощью команды
node --experimental-specifier-resolution=node index.js
Ответ №3:
Мое выдавало ту же ошибку, возможно, из-за используемой версии, я решил::
const express = require('express');
const app = express();
const PORT = 3000;
e нет package.json: «узел index.js «