Về "*.d.ts" trong TypeScript
Tôi tò mò về các tệp khai báo .d.ts. Ai đó đã nói với tôi rằng các tệp .d.ts giống như các tệp tiêu đề .h trong ngôn ngữ lập trình C & C++, tuy nhiên, các tệp .d.ts có vẻ không hoạt động hoàn toàn giống như vậy. Hiện tại, tôi đang không hiểu cách sử dụng đúng các tệp .d.ts.
Có vẻ như tôi không thể thêm các tệp .js hoặc .ts của mình vào các tệp .d.ts, vì vậy cách duy nhất để dự án của tôi hoạt động là nếu nó chứa cả ba loại tệp. Các câu hỏi của tôi là:
Mối quan hệ giữa ba tệp đó là gì?
Làm thế nào tôi có thể sử dụng tệp
*.d.ts, có nghĩa là tôi có thể xóa vĩnh viễn tệp*.tskhông?Nếu vậy, làm thế nào để tệp
*.d.tsbiết tệp JS nào đang ánh xạ với chính nó?
Câu trả lời #1
Tệp "d.ts" được sử dụng để cung cấp thông tin kiểu TypeScript về một API được viết bằng JavaScript. Ý tưởng là bạn đang sử dụng một cái gì đó như jQuery hoặc underscore, một thư viện JavaScript hiện có. Bạn muốn sử dụng chúng từ mã TypeScript của mình.
Thay vì viết lại jquery hoặc underscore hay bất cứ thứ gì bằng typescript, bạn có thể viết file d.ts, chỉ chứa các chú thích kiểu. Sau đó từ code typescript của bạn, bạn sẽ nhận được lợi ích của kiểm tra kiểu tĩnh trong typescript trong khi vẫn sử dụng thư viện JS thuần túy.
Điều này hoạt động nhờ vào ràng buộc của TypeScript không cho phép bạn thêm phần mở rộng ".ts" vào cuối câu lệnh import. Vì lý do đó, khi bạn tham chiếu một tập tin nào đó, giả sử my-module.js, nếu có một my-module.d.ts nằm cạnh nó, thì TypeScript sẽ bao gồm nội dung của nó:
src/
my-module.js
my-module.d.ts
index.ts
my-module.js
const thing = 42;
module.exports = { thing };
my-module.d.ts
export declare const thing: number;
index.ts
import { thing } from "./my-module"; // <- no extension
// runtime implementation of `thing` is taken from ".js"
console.log(thing); // 42
// type declaration of `thing` is taken from ".d.ts"
type TypeOfThing = typeof thing; // number
Câu trả lời #2
d đại diện cho các Tệp Khai báo:
Khi một tập lệnh TypeScript được biên dịch, có một tùy chọn để tạo ra một tệp khai báo (với phần mở rộng .d.ts) hoạt động như một giao diện cho các thành phần trong JavaScript đã biên dịch. Trong quá trình này, trình biên dịch sẽ loại bỏ tất cả các thân hàm và phương thức và chỉ giữ lại các chữ ký của các kiểu được xuất ra. Tệp khai báo kết quả sau đó có thể được sử dụng để mô tả các kiểu TypeScript ảo được xuất ra của một thư viện hoặc mô-đun JavaScript khi một nhà phát triển bên thứ ba sử dụng nó từ TypeScript.
Khái niệm về các tệp khai báo tương tự với khái niệm về tệp tiêu đề trong C/C++.
declare module arithmetics {
add(left: number, right: number): number;
subtract(left: number, right: number): number;
multiply(left: number, right: number): number;
divide(left: number, right: number): number;
}
Các tệp khai báo kiểu có thể được viết thủ công cho các thư viện JavaScript hiện có, như đã được thực hiện cho jQuery và Node.js.
Các bộ sưu tập lớn các tệp khai báo cho các thư viện JavaScript phổ biến được lưu trữ trên GitHub trong DefinitelyTyped và Typings Registry. Một tiện ích dòng lệnh gọi là typings được cung cấp để giúp tìm kiếm và cài đặt các tệp khai báo từ các kho lưu trữ.
Câu trả lời #3
Tôi đã học được những điều sau từ việc phải tỉ mỉ lập bản đồ một dự án JavaScript bằng cách sử dụng các tệp .d.ts.
Sử dụng một tệp .d.ts để ánh xạ JavaScript yêu cầu bạn đặt tên tệp .d.ts giống như tên tệp .js của bạn. Mỗi tệp .js cần được giữ cùng vị trí (giữ trong cùng thư mục) với tệp .d.ts có cùng tên. Chỉ định mã JS/TS cần các kiểu từ các tệp .d.ts đến các tệp .d.ts đó.
ví dụ: test.js và test.d.ts nằm trong thư mục testdir/, thì bạn nhập nó như sau trong một component của React:
import * as Test from "./testdir/test";
Tệp .d.ts đã được xuất dưới dạng một namespace như sau:
export as namespace Test;
export interface TestInterface1{}
export class TestClass1{}
Câu trả lời #4
Ví dụ minh họa cho một trường hợp cụ thể:
Giả sử bạn có my-module mà bạn đang chia sẻ qua npm.
Bạn cài đặt nó bằng npm install my-module
Bạn sử dụng nó như sau:
import * as lol from 'my-module';
const a = lol('abc', 'def');
Logic của module nằm toàn bộ trong index.js:
module.exports = function(firstString, secondString) {
// your code
return result
}
Để thêm kiểu, tạo một tệp index.d.ts:
declare module 'my-module' {
export default function anyName(arg1: string, arg2: string): MyResponse;
}
interface MyResponse {
something: number;
anything: number;
}
Câu trả lời số 5
Như @takeshin đã nói, .d là viết tắt của file khai báo cho TypeScript (.ts).
Một vài điểm cần được làm rõ trước khi tiếp tục trả lời bài viết này -
- Typescript là phần mở rộng cú pháp của JavaScript.
- Typescript không chạy độc lập, nó cần được biên dịch sang javascript (chuyển đổi từ typescript sang javascript)
- "Định nghĩa kiểu" và "Kiểm tra kiểu" là các chức năng bổ sung quan trọng mà TypeScript cung cấp hơn so với JavaScript. (kiểm tra sự khác biệt giữa TypeScript và JavaScript)
Nếu bạn đang tự hỏi liệu TypeScript chỉ là một tập hợp cú pháp mở rộng, nó mang lại những lợi ích gì - https://basarat.gitbooks.io/typescript/docs/why-typescript.html#the-typescript-type-system
Để trả lời bài viết này -
Như chúng ta đã thảo luận, TypeScript là một siêu tập của JavaScript và cần được biên dịch sang JavaScript. Vì vậy, nếu một thư viện hoặc mã của bên thứ ba được viết bằng TypeScript, nó cuối cùng sẽ được chuyển đổi sang JavaScript, điều này có thể được sử dụng bởi dự án JavaScript nhưng ngược lại thì không đúng.
Ví dụ -
Nếu bạn cài đặt thư viện javascript -
npm install --save mylib
và thử nhập nó vào mã typescript -
import * from "mylib";
bạn sẽ gặp lỗi.
"Không tìm thấy module 'mylib'."
Như @Chris đã đề cập, nhiều thư viện như underscore, Jquery đã được viết bằng javascript. Thay vì viết lại những thư viện đó cho các dự án typescript, cần một giải pháp thay thế.
Để làm điều này, bạn có thể cung cấp tệp khai báo kiểu trong thư viện javascript có tên là *.d.ts, như trong ví dụ trên mylib.d.ts. Tệp khai báo chỉ cung cấp khai báo kiểu của các hàm và biến được định nghĩa trong tệp javascript tương ứng.
Bây giờ khi bạn thử -
import * from "mylib";
mylib.d.ts được nhập khẩu, nó đóng vai trò như một giao diện giữa mã thư viện JavaScript và dự án TypeScript.
Câu trả lời số 6
Câu trả lời này giả sử bạn có một số JavaScript mà bạn không muốn chuyển sang TypeScript, nhưng bạn muốn tận dụng kiểm tra kiểu với những thay đổi tối thiểu đối với .js của mình. Một tệp .d.ts rất giống với tệp header C hoặc C++. Mục đích của nó là để định nghĩa một giao diện. Dưới đây là một ví dụ:
mashString.d.ts
/** Makes a string harder to read. */
declare function mashString(
/** The string to obscure */
str: string
):string;
export = mashString;
mashString.js
// @ts-check
/** @type {import("./mashString")} */
module.exports = (str) => [...str].reverse().join("");
main.js
// @ts-check
const mashString = require("./mashString");
console.log(mashString("12345"));
Mối quan hệ ở đây là: mashString.d.ts định nghĩa một giao diện, mashString.js triển khai giao diện và main.js sử dụng giao diện.
Để kiểm tra kiểu dữ liệu hoạt động, bạn thêm // @ts-check vào các tệp .js của bạn. Nhưng điều này chỉ kiểm tra rằng main.js sử dụng giao diện đúng cách. Để đảm bảo rằng mashString.js cũng triển khai nó đúng cách, chúng ta thêm /** @type {import("./mashString")} */ trước khi xuất.
Bạn có thể tạo các file .d.ts ban đầu của mình bằng cách sử dụng tsc -allowJs main.js -d rồi chỉnh sửa chúng theo yêu cầu thủ công để cải thiện kiểm tra kiểu và tài liệu.
Trong hầu hết các trường hợp, phần triển khai và giao diện có cùng tên, ở đây là mashString. Nhưng bạn có thể có các phần triển khai thay thế. Ví dụ, chúng ta có thể đổi tên mashString.js thành reverse.js và có một encryptString.js thay thế.
