jquery - ติดตั้งการกำหนดประเภท TypeScript หลายตัวที่ประกาศตัวแปร global เดียวกัน
ฉันกำลังสร้างแอปพลิเคชันโดยใช้ TypeScript, Node และ Electron
ฉันกำลังใช้ jQuery ในแอปพลิเคชันและฉันได้ติดตั้งแพ็กเกจ @types/jquery เพื่อให้มีคำแนะนำ Intellisense
ต่อไปฉันสร้างการทดสอบโดยใช้ mocha และ spectron Spectron ใช้ประโยชน์จาก webdriverio และเปิดเผย API ของมันผ่านคุณสมบัติบางอย่าง ฉันจำเป็นต้องใช้คุณสมบัติเหล่านี้ ดังนั้นฉันจึงติดตั้ง @types/webdriverio เพื่อให้ได้รับคำแนะนำ intellisense
ตอนนี้ ทุกครั้งที่ฉันรันเครื่องมือ tsc เพื่อคอมไพล์โปรเจกต์ ฉันจะได้รับข้อผิดพลาดดังต่อไปนี้:
node_modules/@types/jquery/index.d.ts(36,15): error TS2451: Cannot redeclare block-scoped variable '$'.
node_modules/@types/webdriverio/index.d.ts(1898,18): error TS2451: Cannot redeclare block-scoped variable '$'.
node_modules/@types/webdriverio/index.d.ts(1899,18): error TS2451: Cannot redeclare block-scoped variable '$'.
ปัญหาคือทั้งสองแพ็กเกจประกาศตัวแปร $ แบบ global คุณสามารถตรวจสอบได้ในหน้าของพวกเขาบน npm ภายใต้ "Global values" ด้วยเช่นกัน:
https://www.npmjs.com/package/@types/jquery
https://www.npmjs.com/package/@types/webdriverio
สิ่งที่ฉันไม่เข้าใจก็คือทำไม tsc ถึงพยายามคอมไพล์พวกมันด้วยกันทั้งที่ฉันไม่ได้ใช้ jquery และ webdriverio ในไฟล์ .ts เดียวกัน?
นอกจากนี้ แม้ว่าฉันจะคอมเมนต์โค้ดทดสอบออก ซึ่งทำให้ฉันไม่อ้างอิง webdriverio ที่ไหนเลย แต่เมื่อฉันรัน tsc ฉันก็ยังได้รับข้อผิดพลาดเหมือนเดิม อาจเป็นเพราะ tsc กำลังคอมไพล์ซอร์สทั้งหมดใน node_modules/@types พร้อมกัน แท้จริงแล้ว ถ้าฉันลบโฟลเดอร์ node_modules/@types/webdriverio ออกและรัน tsc อีกครั้ง ฉันก็จะไม่พบข้อผิดพลาด (แน่นอน ตราบใดที่ฉันยังคงคอมเมนต์โค้ดทดสอบอยู่)
นี่คือไฟล์ tsconfig.json ของฉันซึ่งอยู่ในโฟลเดอร์รากของโปรเจกต์:
{
"compilerOptions": {
"target": "ES6",
"module": "commonjs",
"sourceMap": false,
"inlineSourceMap": true,
"inlineSources": true,
"declaration": false,
"outDir": "dist"
},
"include": [
"src/**/*"
]
}
ซอร์สโค้ดทั้งหมดของฉันอยู่ในไดเรกทอรี src การทดสอบอยู่ใน src/test
มีการตั้งค่าใดบ้างที่ฉันสามารถทำเพื่อให้ประเภทของ webdriverio และ jquery แยกออกจากกันในเวลาคอมไพล์? นอกจากนี้ ฉันยังเคยเห็นตัวอย่างโค้ดที่เขียนเป็น js ที่ใช้ทั้งสองพร้อมกัน: สิ่งนี้ไม่สามารถทำได้ใน typescript หรือ?
คำตอบ #1
มันนานมากแล้ว แต่ฉันพบวิธีแก้ปัญหาแล้ว!
คุณจำเป็นต้องกำหนด tsconfig สองชุดแยกกัน: หนึ่งชุดสำหรับโปรเจกต์หลักและอีกหนึ่งชุดสำหรับการทดสอบ
tsconfig.project.json
{
"compilerOptions": {
"target": "ES6",
"module": "commonjs",
"sourceMap": false,
"inlineSourceMap": true,
"inlineSources": true,
"watch": false,
"declaration": false,
"outDir": "dist",
"typeRoots": ["./typings"],
},
"include": [
"src/**/*"
],
"exclude": [
"src/test/*"
]
}
tsconfig.test.json
{
"compilerOptions": {
"target": "ES6",
"module": "commonjs",
"sourceMap": false,
"inlineSourceMap": true,
"inlineSources": true,
"watch": false,
"declaration": false,
"outDir": "dist",
"typeRoots": ["./typings"],
},
"include": [
"src/test/*"
]
}
จากนั้น ในไฟล์ package.json ให้กำหนดสคริปต์สองตัวที่แตกต่างกันเพื่อรัน tsc กับ tsconfig สองตัวที่คุณเพิ่งกำหนดไว้:
{
...
"scripts": {
"test": "tsc -p tsconfig.test.json && mocha --exit dist/test",
"tsc": "tsc -p tsconfig.project.json",
...
},
...
}
ประเด็นสำคัญคือการกำหนดค่า typeRoots ซึ่งเขียนทับพฤติกรรมเริ่มต้นของคอมไพเลอร์ TypeScript พฤติกรรมเริ่มต้นคือการโหลดทุกแพ็กเกจที่กำหนดไว้ภายใต้โฟลเดอร์ @types ใด ๆ (ดังนั้นทุก @types ที่ติดตั้งในโฟลเดอร์ node_modules จะถูกนำมารวม) โดยการเขียนทับการกำหนดค่านี้ @types ใน node_modules จะถูกรวมเฉพาะเมื่อมีการอ้างอิง หรือคุณสามารถแทนที่การกำหนดค่า typeRoots ด้วย
"types": []
จาก https://www.typescriptlang.org/docs/handbook/tsconfig-json.html
@types, typeRoots และ types
โดยดีฟอลต์ แพ็กเกจ "@types" ที่มองเห็นทั้งหมดจะถูกรวมอยู่ในการคอมไพล์ของคุณ แพ็กเกจใน node_modules/@types ของโฟลเดอร์ใด ๆ ที่ครอบคลุมถือว่ามองเห็นได้; โดยเฉพาะหมายถึงแพ็กเกจภายใน ./node_modules/@types/, ../node_modules/@types/, ../../node_modules/@types/ และอื่น ๆ ต่อไป
หากระบุ typeRoots จะรวมเฉพาะแพ็กเกจที่อยู่ใต้ typeRoots เท่านั้น
...
ระบุ "types": [] เพื่อปิดการรวมแพ็กเกจ @types อัตโนมัติ
จำไว้ว่าการรวมอัตโนมัติมีความสำคัญก็ต่อเมื่อคุณกำลังใช้ไฟล์ที่มีการประกาศแบบทั่วโลก (ตรงข้ามกับไฟล์ที่ประกาศเป็นโมดูล). ตัวอย่างเช่น หากคุณใช้คำสั่ง import "foo", TypeScript อาจยังคงค้นหาผ่านโฟลเดอร์ node_modules และ node_modules/@types เพื่อค้นหาแพ็กเกจ foo.
อีกประเด็นสำคัญคือการแยกไฟล์คอนฟิก ด้วยวิธีนี้คุณสามารถยกเว้นไฟล์ทดสอบเมื่อคอมไพล์โปรเจกต์หลักและในทางกลับกัน สิ่งนี้สำคัญเพราะโปรเจกต์หลักรวม jquery ในขณะที่ไฟล์ทดสอบรวม webdriverio การคอมไพล์พวกมันรวมกันคุณจะได้ข้อผิดพลาดเหมือนกับที่อธิบายในคำถาม
