โมดูลนำเข้า typescript es6“ ไฟล์ไม่ใช่ข้อผิดพลาดของโมดูล”


129

ฉันใช้ typescript 1.6 กับไวยากรณ์โมดูล es6

ไฟล์ของฉันคือ:

test.ts:

module App {
  export class SomeClass {
    getName(): string {
      return 'name';
    }
  }
}

main.ts:

import App from './test';

var a = new App.SomeClass();

เมื่อฉันพยายามรวบรวมmain.tsไฟล์ฉันได้รับข้อผิดพลาดนี้:

ข้อผิดพลาด TS2306: ไฟล์ 'test.ts' ไม่ใช่โมดูล

ฉันจะทำมันให้สำเร็จได้อย่างไร?


ฉันมีปัญหานี้ฉันไม่มีตัวสร้างในชั้นเรียนเพิ่มหนึ่งตัวและปัญหาก็หายไป
dorriz

คำตอบ:


141

ขยาย - เพื่อให้รายละเอียดเพิ่มเติมตามความคิดเห็นบางส่วน

ข้อผิดพลาด

ข้อผิดพลาด TS2306: ไฟล์ 'test.ts' ไม่ใช่โมดูล

มาจากข้อเท็จจริงที่อธิบายไว้ที่นี่http://exploringjs.com/es6/ch_modules.html

17. โมดูล

บทนี้อธิบายวิธีการทำงานของโมดูลในตัวใน ECMAScript 6

17.1 ภาพรวม

ใน ECMAScript 6 โมดูลจะถูกเก็บไว้ในไฟล์ มีหนึ่งโมดูลต่อไฟล์และหนึ่งไฟล์ต่อโมดูล คุณมีสองวิธีในการส่งออกสิ่งต่างๆจากโมดูล สองวิธีนี้สามารถผสมกันได้ แต่โดยปกติแล้วควรใช้แยกกัน

17.1.1 การส่งออกหลายชื่อ

สามารถมีการส่งออกหลายชื่อ:

//------ lib.js ------
export const sqrt = Math.sqrt;
export function square(x) {
    return x * x;
}
export function diag(x, y) {
    return sqrt(square(x) + square(y));
}
...

17.1.2 การส่งออกเริ่มต้นเดียว

สามารถมีการส่งออกเริ่มต้นรายการเดียว ตัวอย่างเช่นฟังก์ชัน:

//------ myFunc.js ------
export default function () { ··· } // no semicolon!

จากข้อมูลข้างต้นเราต้องการexportเป็นส่วนหนึ่งของไฟล์test.js มาปรับเนื้อหากันดังนี้:

// test.js - exporting es6
export module App {
  export class SomeClass {
    getName(): string {
      return 'name';
    }
  }
  export class OtherClass {
    getName(): string {
      return 'name';
    }
  }
}

และตอนนี้เราสามารถนำเข้าได้ด้วยสามวิธีต่อไปนี้:

import * as app1 from "./test";
import app2 = require("./test");
import {App} from "./test";

และเราสามารถบริโภคสิ่งที่นำเข้าได้เช่นนี้:

var a1: app1.App.SomeClass  = new app1.App.SomeClass();
var a2: app1.App.OtherClass = new app1.App.OtherClass();

var b1: app2.App.SomeClass  = new app2.App.SomeClass();
var b2: app2.App.OtherClass = new app2.App.OtherClass();

var c1: App.SomeClass  = new App.SomeClass();
var c2: App.OtherClass = new App.OtherClass();

และเรียกใช้เมธอดเพื่อดูการทำงาน:

console.log(a1.getName())
console.log(a2.getName())
console.log(b1.getName())
console.log(b2.getName())
console.log(c1.getName())
console.log(c2.getName())

ส่วนดั้งเดิมพยายามที่จะช่วยลดจำนวนความซับซ้อนในการใช้งานเนมสเปซ

ส่วนเดิม:

ฉันขอแนะนำอย่างยิ่งให้ตรวจสอบคำถาม & คำตอบนี้:

ฉันจะใช้เนมสเปซกับโมดูลภายนอก TypeScript ได้อย่างไร

ขอยกประโยคแรก:

อย่าใช้ "เนมสเปซ" ในโมดูลภายนอก

อย่าทำแบบนี้

อย่างจริงจัง. หยุด.

...

ในกรณีนี้เราก็ไม่จำเป็นต้องทำภายในของmodule test.tsนี่อาจเป็นเนื้อหาของการปรับเปลี่ยนtest.ts:

export class SomeClass
{
    getName(): string
    {
        return 'name';
    }
}

อ่านเพิ่มเติมที่นี่

ส่งออก =

ในตัวอย่างก่อนหน้านี้เมื่อเราใช้ตัวตรวจสอบความถูกต้องแต่ละโมดูลจะส่งออกเพียงค่าเดียว ในกรณีเช่นนี้การใช้สัญลักษณ์เหล่านี้ผ่านชื่อที่มีคุณสมบัติเหมาะสมเป็นเรื่องยุ่งยากเมื่อตัวระบุเดียวจะทำได้เช่นกัน

export =ไวยากรณ์ระบุวัตถุเดียวที่ถูกส่งออกจากโมดูล ซึ่งอาจเป็นคลาสอินเทอร์เฟซโมดูลฟังก์ชันหรือ enum เมื่อนำเข้าสัญลักษณ์ที่ส่งออกจะถูกใช้โดยตรงและไม่มีคุณสมบัติตามชื่อใด ๆ

เราสามารถบริโภคได้ในภายหลังดังนี้:

import App = require('./test');

var sc: App.SomeClass = new App.SomeClass();

sc.getName();

อ่านเพิ่มเติมที่นี่:

การโหลดโมดูลเสริมและสถานการณ์การโหลดขั้นสูงอื่น ๆ

ในบางกรณีคุณอาจต้องการโหลดโมดูลภายใต้เงื่อนไขบางประการเท่านั้น ใน TypeScript เราสามารถใช้รูปแบบที่แสดงด้านล่างเพื่อใช้สถานการณ์นี้และสถานการณ์การโหลดขั้นสูงอื่น ๆ เพื่อเรียกใช้ตัวโหลดโมดูลโดยตรงโดยไม่สูญเสียความปลอดภัยของประเภท

คอมไพเลอร์ตรวจพบว่าแต่ละโมดูลถูกใช้ใน JavaScript ที่ปล่อยออกมาหรือไม่ สำหรับโมดูลที่ใช้เป็นส่วนหนึ่งของระบบชนิดเท่านั้นไม่ต้องมีการเรียกใช้ การคัดแยกการอ้างอิงที่ไม่ได้ใช้นี้เป็นการเพิ่มประสิทธิภาพที่ดีและยังช่วยให้สามารถโหลดโมดูลเหล่านั้นได้อีกด้วย

แนวคิดหลักของรูปแบบคือคำสั่ง import id = require ('... ') ทำให้เราสามารถเข้าถึงประเภทที่โมดูลภายนอกเปิดเผยได้ ตัวโหลดโมดูลถูกเรียกใช้ (ผ่านความต้องการ) แบบไดนามิกดังแสดงในบล็อก if ด้านล่าง สิ่งนี้ใช้ประโยชน์จากการเพิ่มประสิทธิภาพการอ้างอิงเพื่อให้โมดูลโหลดเมื่อจำเป็นเท่านั้น เพื่อให้รูปแบบนี้ใช้งานได้สิ่งสำคัญคือสัญลักษณ์ที่กำหนดผ่านการนำเข้าจะถูกใช้ในตำแหน่งประเภทเท่านั้น (กล่าวคือไม่ควรอยู่ในตำแหน่งที่จะถูกปล่อยลงใน JavaScript)


1
แต่สิ่งนี้: import App = ต้องใช้ ('./ test'); ไม่ใช่ไวยากรณ์ของโมดูล es6 นี่คือ js ทั่วไป ฉันสามารถใช้ไวยากรณ์โมดูล es6 ได้หรือไม่
Bazinga

@JsIsAwesome คุณกำลังพยายามผสมโมดูล JS กับโมดูล typescript คุณต้องใช้อย่างใดอย่างหนึ่งไม่ใช่ผสมทั้งสองอย่าง
JJJ

คำตอบนี้ไม่ได้อ้างถึงไวยากรณ์ ES6
phiresky

@phiresky คุณหมายถึงอะไร?
Radim Köhler

1
ขอบคุณเยี่ยมมาก
phiresky

24

คำตอบข้างต้นถูกต้อง แต่ในกรณี ... มีข้อผิดพลาดเดียวกันใน VS Code ต้องบันทึกใหม่ / คอมไพล์ไฟล์ใหม่ที่เกิดข้อผิดพลาด


3
สิ่งนี้ได้ผลสำหรับฉัน ฉันเพียงแค่ลบเซมิโคลอนเพิ่มใหม่และบันทึกไฟล์อีกครั้งจากนั้นเรียกใช้ Webpack ช่วงเวลาที่ดีในการมีชีวิตอยู่
Ray Hogan

1
ฉันคุ้นเคยกับ Webstorm และไม่ทราบว่าไฟล์ไม่ได้รับการบันทึกโดยอัตโนมัติใน VS Code คำตอบนี้ช่วยให้ฉันเจ็บปวดมากขอบคุณ
cib

มีการตั้งค่าสำหรับบันทึกอัตโนมัติใน VS Code ฉันไม่ได้ใช้มันเพราะ VS Code สำรองไฟล์ที่ไม่ได้บันทึกไว้แล้วและฉันก็ไม่ได้ใช้ git เสมอไป
aamarks

13

ฉันจะทำมันให้สำเร็จได้อย่างไร?

ตัวอย่างของคุณประกาศ typescript <1.5 โมดูลภายในซึ่งตอนนี้เรียกว่าnamespace module App {}ตอนนี้ไวยากรณ์เก่าเทียบเท่ากับnamespace App {}. ด้วยเหตุนี้การทำงานดังต่อไปนี้:

// test.ts
export namespace App {
    export class SomeClass {
        getName(): string {
            return 'name';
        }
    }
}

// main.ts
import { App } from './test';
var a = new App.SomeClass();

ที่ถูกกล่าว ...

พยายามหลีกเลี่ยงการเอ็กซ์พอร์ตเนมสเปซและส่งออกโมดูลแทน (ซึ่งก่อนหน้านี้เรียกว่าโมดูลภายนอก ) หากจำเป็นคุณสามารถใช้เนมสเปซในการนำเข้าด้วยรูปแบบการนำเข้าเนมสเปซดังนี้:

// test.ts
export class SomeClass {
    getName(): string {
        return 'name';
    }
}

// main.ts
import * as App from './test'; // namespace import pattern
var a = new App.SomeClass();

1
มันยังคงเป็นแนวทางปฏิบัติที่ดี? ตามคำตอบนี้ ( stackoverflow.com/a/35706271/2021224 ) พยายามนำเข้าฟังก์ชันหรือคลาสเช่นนี้แล้วเรียกใช้ - "ผิดกฎหมายตามข้อกำหนด ES6"
Andrey Prokhorov

2

นอกจากคำตอบของอ. ทิมแล้วยังมีบางครั้งที่ไม่ได้ผลดังนั้นคุณต้อง:

  1. เขียนสตริงการนำเข้าใหม่โดยใช้ Intellisense บางครั้งวิธีนี้ช่วยแก้ปัญหาได้
  2. รีสตาร์ท VS Code

1
เหมือนกันสำหรับ stackblitz - ไฟล์คอมไพล์ใหม่ที่นำเข้าโมดูลและทุกอย่างทำงานได้ดีไชโย
godblessstrawberry

ฉันยังพบสิ่งนี้เมื่อรหัสของฉันไม่ได้จัดรูปแบบถูกต้อง VSCode เยื้องรหัสคลาสคัดลอก + วางของฉันเมื่อฉันแบ่งคลาสออกเป็นไฟล์ของตัวเองและ VSCode เยื้องทุกอย่างตามหลังexport class... {ซึ่งไม่ชอบเชิงมุมทำให้ฉันมีปัญหานี้ หลังจากแก้ไขการจัดรูปแบบคอมไพล์โดยไม่มีปัญหา
Guy Park

0

นอกจากคำตอบของ Tim แล้วปัญหานี้ยังเกิดขึ้นกับฉันเมื่อฉันกำลังแยกการปรับโครงสร้างไฟล์ใหม่โดยแยกออกเป็นไฟล์ของพวกเขาเอง

ด้วยเหตุผลบางประการ VSCode เยื้องบางส่วนของโค้ด [คลาส] ของฉันซึ่งทำให้เกิดปัญหานี้ สิ่งนี้ยากที่จะสังเกตเห็นในตอนแรก แต่หลังจากที่ฉันรู้ว่ารหัสถูกเยื้องฉันจึงจัดรูปแบบรหัสและปัญหาก็หายไป

ตัวอย่างเช่นทุกอย่างหลังจากบรรทัดแรกของนิยามคลาสถูกเยื้องอัตโนมัติในระหว่างการวาง

export class MyClass extends Something<string> {
    public blah: string = null;

    constructor() { ... }
  }

0

ไฟล์จำเป็นต้องเพิ่มส่วนประกอบจากคอร์ดังนั้นจึงเพิ่มการนำเข้าต่อไปนี้ที่ด้านบน

นำเข้า {Component} จาก "@ angular / core";

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.