#javascript #typescript
#javascript #typescript
Вопрос:
В моем проекте есть js-файл, который мне нужно использовать из ts-файла.
Путь к файлу js «javascript/jsToConsume.js «.
Путь к файлу ts — «typescript/client.ts»
Я добавил файл объявлений по пути «typings/internal/jsToConsume.d.ts», содержимое которого выглядит следующим образом:
declare namespace jsToConsume{
export function func1(): void;
}
В моем client.ts я пытаюсь использовать его:
///<reference path="../typings/internal/jsToConsume.d.ts" />
import * as jsToConsume from '../javascript/jsToConsume'
Но '../javascript/jsToConsume'
отмечен красной строкой, и я получаю следующую ошибку:
TS2307: не удается найти модуль ‘../javascript/jsToConsume’
Кстати, код работает безупречно, это просто ошибка TSC.
javascript/jsToConsume.js:
function func1(){
return "Hello World";
}
exports.func1 = func1;
Любая помощь будет высоко оценена!
Комментарии:
1. используете ли вы SystemJS для загрузки файлов? Если вы это сделаете, вам следует настроить его, чтобы правильно сопоставить импорт с фактическим файлом js. 🙂
2. @toskv я этого не делаю. это серверный проект в Node.js .
3. вам все равно нужно будет загрузить правильный файл через require. : D может быть, разобраться в этом?
4. @toskv моя версия JavaScript — ES6, и я переношу свой TypeScript на ES6, поэтому я не использую «требовать». Этот синтаксис отлично работает для меня, когда я использую сторонние библиотеки, которые установлены в node_modules .
5. @Alon, node_modules находится в вашей переменной NODE_PATH (или какой-либо другой эквивалентной переменной), а файл, который вы пытаетесь импортировать, — нет. В этом случае вам нужно либо изменить NODE_PATH, либо указать путь к вашему js-файлу
Ответ №1:
Если вы передаете --allowJs
флаг, как true
в вашем tsconfig.json
, он сообщает компилятору TypeScript также скомпилировать файлы JavaScript. Поэтому, если для этого флага установлено значение true, TypeScript будет знать о модулях, которые вы определили в своих файлах JavaScript, и вам не нужно будет выполнять какие-либо дополнительные манипуляции с файлами объявлений.
Поэтому пример tsconfig.json
файла может выглядеть следующим образом:
{
"compilerOptions": {
"allowJs": true
"module": "commonjs",
"noImplicitAny": true,
"target": "es6"
},
"exclude": [
"node_modules"
]
}
(https://www.typescriptlang.org/docs/handbook/compiler-options.html )
Конечно, файл конфигурации будет полностью зависеть от вашего проекта, но вы просто добавите "allowJS": true
его в качестве одного из своих "compilerOptions"
.
Примечание: Это доступно с версии TypeScript 1.8
Соответствующие примечания к выпуску находятся здесь:
— РЕДАКТИРОВАТЬ —
В ответ на комментарии о том, что требуются типы вместе с вашим внутренним импортом JS, я придумал следующее. Однако, если вам так сложно добавлять типы в ваши модули JavaScript, я бы просто предложил преобразовать файл в TypeScript и ввести весь ваш экспорт по минимуму (на самом деле, оглядываясь назад на это редактирование, это кажется действительно ненужным, если только по какой-либо причине абсолютно невозможно преобразовать вашОт JS до TS). Но в любом случае…
Вы все равно передадите "allowJs": true
свой tsconfig.json
, но вы можете создавать интерфейсы для нужных вам модулей JavaScript, а затем вводить импорт в свой TS-файл. Ниже приведен пример, в котором JS-файл и TS-файл немного более конкретизированы, чтобы показать возможности:
Структура папок
src
| - javascript
| | - jsToConsume.js
| - typescript
| | - client.ts
typings
| - typings.d.ts
tsconfig.json
jsToConsume.js
export const yourHair = (adjective) => {
return `Your hair is ${adjective}`;
}
export let jam = 'sweet';
export class AnotherClass {
constructor() {
this.foo = 'bar';
}
}
export default class Hungry {
constructor() {
this.hungry = true;
}
speak() {
return 'More cake please';
}
}
typings.d.ts
declare interface jsToConsumeModule {
yourHair: (adjective: string) => string;
jam: string;
AnotherClass: AnotherClassConstructor;
}
declare interface Hungry {
hungry: boolean;
speak: () => string;
}
declare interface HungryConstructor {
new (): Hungry;
}
declare interface AnotherClass {
foo: string;
}
declare interface AnotherClassConstructor {
new (): AnotherClass;
}
client.ts
import { yourHair as _yourHair_ } from './../javascript/jsToConsume';
const yourHair: (adjective: string) => string = _yourHair_;
import * as _jsToConsume_ from './../javascript/jsToConsume';
const jsToConsume: jsToConsumeModule = _jsToConsume_;
import _Hungry_ from './../javascript/jsToConsume';
const Hungry: HungryConstructor = _Hungry_;
Итак, при импорте отдельных элементов и значений по умолчанию из модуля просто укажите каждому желаемый тип. Затем вы можете предоставить интерфейс для общедоступного экспорта модуля при использовании import * as ...
.
Обратите внимание, но у вас должна быть действительно веская причина, по которой вы не хотите просто менять свои JS-файлы на TS. Подумайте на мгновение, что вам нужны типы для ваших файлов, и вы можете контролировать их, поскольку они являются внутренними для вашего проекта, так что это звучит как точный пример использования, почему TS существует. Вы не можете управлять внешними модулями, поэтому вы создаете файлы объявлений, чтобы создать интерфейс для взаимодействия с библиотекой. Если вы полны решимости добавлять типы в свой JavaScript, вы можете сделать это, сделав его TypeScript.
Комментарии:
1. На самом деле это единственный способ сделать это правильно. Именно так вы заставляете JS и TS работать вместе с модулями. Все остальное — это хак
2. Я не хочу компилировать js. Я только хочу иметь возможность использовать внутренний файл js так же, как и с внешними сторонними библиотеками. Я могу найти его в node_modules и имитировать то, что делают другие библиотеки, но я хочу, чтобы он находился в моем проекте, а не в node_modules.
3. Извините, возможно, моя формулировка вводит в заблуждение, но этот флаг делает именно это. Оставьте свой файл там, где он есть, и компилятор прочитает файл и узнает о его экспорте… Вам не нужно будет перемещать файл в node_modules, и единственная причина, по которой вы добавили бы файл объявления, — это присвоить типы экспортируемым свойствам и методам.
4. Просто убедитесь, что вы не исключаете свои js-файлы (кроме node_modules) в вашем
tsconfig
5. Подводя итог,
allowjs
флаг предназначен именно для ситуации, когда ваш проект включает в себя как файлы TypeScript, так и JavaScript
Ответ №2:
Для внешних модулей проблема в строке:
import * as jsToConsume from '../javascript/jsToConsume'
Код будет работать даже без него, потому что у вас есть ссылка:
///<reference path="../typings/internal/jsToConsume.d.ts" />
Обычный способ использования внешнего модуля — иметь только одну строку (https://www.typescriptlang.org/docs/handbook/modules.html ):
import * as jsToConsume from 'jsToConsume';
И еще лучше переименовать пространство имен в module:
declare module jsToConsume{...}
Это было для внешних модулей
Но если у вас есть только внутренние модули, лучше использовать модули без пространства имен, просто:
export function func1(): void;
Затем вы можете использовать его как:
import {func1} from '../javascript/jsToConsume';
или
import * as someName from '../javascript/jsToConsume';
someName.func1();
Комментарии:
1. Спасибо, я удалил инструкцию «import» и сохранил только ссылку на сценарий, и это устранило ошибку. Однако я не согласен с тем, что ключевое слово «module» лучше, чем «пространство имен». Afaik, больше нет внешних и внутренних модулей. Внешние модули теперь просто «модули», а внутренние модули — «пространства имен». Ключевое слово «module» предназначено для обратной поддержки. Смотрите: typescriptlang.org/docs/handbook/namespaces.html
2. Извините, я только что увидел, что это на самом деле мне не помогло. Это устранило ошибку TSC, но когда я попытался запустить свой проект, я получил сообщение об ошибке «jsToConsume не определен».
3. Не могли бы вы сказать мне, как я должен изменить свой код именно в моем случае? Старый файл js, который я пытаюсь использовать, использует внешний модуль.
4. Достаточно переписать: объявить модуль jsToConsume, затем использовать: импортировать * как jsToConsume из ‘jsToConsume’; или другим старым способом ссылок: ///<ссылочный путь=»../typings/internal/jsToConsume.d.ts» /> поверх вашего ts-файла используется:jsToConsume.func1(). Этого должно быть достаточно
5. объявить модуль ‘jsToConsume’ . Должно быть в кавычках