我对 .d.ts
声明文件很好奇,因为我是 TypeScript 编程语言的新手。有人告诉我,.d.ts
文件类似于 C & 中的 .h
头文件。然而,C++ 编程语言,.d.ts
文件的工作方式似乎不太一样。目前,我无法理解如何正确使用 .d.ts 文件。我似乎无法将我的 .js
或 .ts
文件添加到 .d.ts
文件中,因此我的项目工作的唯一方法是它包含所有三种文件类型。这似乎是很多文件。为了帮助我更好地理解 .d.ts 文件是如何与 JavaScript & TypeScript,我有一些问题想问。
这三个文件有什么关系?他们之间的关系?如何使用 *.d.ts 文件?这是否意味着我可以永久删除 *.ts 文件?如果是这样,*.d.ts 文件如何知道哪个 JS 文件映射到自己?
如果有人能给我举个例子,那就太好了。
“d.ts”文件用于提供关于用 JavaScript 编写的 API 的 typescript 类型信息。这个想法是你正在使用 jQuery 或 underscore 之类的东西,一个现有的 javascript 库。你想从你的打字稿代码中使用那些。
您可以编写仅包含类型注释的 d.ts 文件,而不是重写 jquery 或下划线或打字稿中的任何内容。然后从您的 typescript 代码中,您可以获得静态类型检查的 typescript 好处,同时仍然使用纯 JS 库。
这要归功于 TypeScript 的限制,即不允许您在 import
语句的末尾添加“.ts”扩展名。因此,当您引用某个文件时,比如说 my-module.js
,如果它旁边有一个 my-module.d.ts
,那么 TypeScript 将包含它的内容:
src/
my-module.js
my-module.d.ts
index.ts
我的模块.js
const thing = 42;
module.exports = { thing };
我的模块.d.ts
export declare const thing: number;
索引.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
d
代表 Declaration Files:
编译 TypeScript 脚本时,可以选择生成声明文件(扩展名为 .d.ts),该文件用作已编译 JavaScript 中组件的接口。在此过程中,编译器会剥离所有函数和方法体,只保留导出类型的签名。然后,当第三方开发人员从 TypeScript 使用它时,生成的声明文件可用于描述 JavaScript 库或模块的导出的虚拟 TypeScript 类型。声明文件的概念类似于 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;
}
可以为现有的 JavaScript 库手动编写类型声明文件,就像 jQuery 和 Node.js 一样。流行的 JavaScript 库的大量声明文件托管在 GitHub 上的definitelyTyped 和 Typings Registry 中。提供了一个名为 typings 的命令行实用程序来帮助从存储库中搜索和安装声明文件。
typings
命令行工具了。最新的方法是通过 @types
命名空间下的 npm 存储库使用类型包装器。有关详细信息,请参阅 github.com/typings/typings/blob/master/README.md
我从不得不使用 .d.ts
文件煞费苦心地映射 JavaScript 项目中学到了以下知识。
使用 .d.ts
文件映射 JavaScript 要求您将 .d.ts
文件命名为与 .js
文件命名相同。每个 .js
文件都需要与同名的 .d.ts
文件保持内联(保存在同一目录中)。将需要类型的 JS/TS 代码从 .d.ts
文件指向 .d.ts
文件。
例如:test.js
和 test.d.ts
在 testdir/
文件夹中,然后您将其导入到 react 组件中:
import * as Test from "./testdir/test";
.d.ts
文件已导出为如下命名空间:
export as namespace Test;
export interface TestInterface1{}
export class TestClass1{}
.d.ts
文件的名称也必须与要导入的包相同。
import x from "x/x.js"
ie 末尾有文件扩展名怎么办?尝试命名 d.ts 文件 x.js.d.ts
但这似乎不起作用
针对特定案例的工作示例:
假设您有通过 npm 共享的 my-module。
您使用 npm install my-module
安装它
你这样使用它:
import * as lol from 'my-module';
const a = lol('abc', 'def');
模块的逻辑都在 index.js
中:
module.exports = function(firstString, secondString) {
// your code
return result
}
要添加类型,请创建文件 index.d.ts
:
declare module 'my-module' {
export default function anyName(arg1: string, arg2: string): MyResponse;
}
interface MyResponse {
something: number;
anything: number;
}
就像@takeshin 说的 .d 代表 typescript (.ts) 的声明文件。
在继续回答这篇文章之前有几点需要澄清 -
Typescript 是 javascript 的语法超集。 Typescript 不能自行运行,它需要被转译成 javascript(typescript 到 javascript 的转换)。“类型定义”和“类型检查”是 typescript 通过 javascript 提供的主要附加功能。 (检查类型脚本和 javascript 之间的区别)
如果您正在考虑打字稿是否只是句法超集,它有什么好处 - https://basarat.gitbooks.io/typescript/docs/why-typescript.html#the-typescript-type-system
要回答这个帖子 -
正如我们所讨论的,typescript 是 javascript 的超集,需要被转译成 javascript。因此,如果一个库或第三方代码是用 typescript 编写的,它最终会转换为 javascript 项目可以使用的 javascript,反之亦然。
对于前 -
如果您安装 javascript 库 -
npm install --save mylib
并尝试在打字稿代码中导入它 -
import * from "mylib";
你会得到错误。
“找不到模块‘mylib’。”
正如@Chris 所提到的,下划线、Jquery 等许多库已经用 javascript 编写。与其为打字稿项目重写这些库,不如使用替代解决方案。
为了做到这一点,您可以在名为 *.d.ts 的 javascript 库中提供类型声明文件,就像上面的例子 mylib.d.ts 一样。声明文件仅提供在相应 javascript 文件中定义的函数和变量的类型声明。
现在当你尝试 -
import * from "mylib";
mylib.d.ts 被导入,它充当 javascript 库代码和 typescript 项目之间的接口。
此答案假定您有一些不想转换为 TypeScript 的 JavaScript,但您希望通过对 .js
进行最小更改来从类型检查中受益。 .d.ts
文件非常类似于 C 或 C++ 头文件。它的目的是定义一个接口。这是一个例子:
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"));
这里的关系是:mashString.d.ts
定义一个接口,mashString.js
实现该接口,main.js
使用该接口。
要使类型检查起作用,请将 // @ts-check
添加到 .js
文件中。但这仅检查 main.js
是否正确使用了接口。为了确保 mashString.js
正确实现它,我们在导出之前添加 /** @type {import("./mashString")} */
。
您可以使用 tsc -allowJs main.js -d
创建初始 .d.ts
文件,然后根据需要手动编辑它们以改进类型检查和文档。
在大多数情况下,实现和接口具有相同的名称,此处为 mashString
。但是你可以有其他的实现。例如,我们可以将 mashString.js
重命名为 reverse.js
并有一个替代 encryptString.js
。
我想我可以在这里加我的 2 美分
// somefile.d.ts
export type SomeItem = {
weight: number
}
export type ItemStorage = {
name: string
items: SomeItem[]
}
// somefile.js
// @ts-check
/** @typedef { import('./somefile.d.ts').SomeItem } SomeItem */
/** @typedef { import('./somefile.d.ts').ItemStorage } ItemStorage */
/**
* @param { StorageItem } item
*/
function doSomething(item) {
item. // intellisense
// your code here
}
这样做的好处是可以逐渐将类型合并到现有的 javascript 项目中。
例如,您在使用 npm 中的“alertifyjs”模块时遇到了问题。
创建“anyNameYoulike.d.ts”(例如,您在 src 文件夹中创建了此文件)在文件中声明模块“alertifyjs”;在 tsconfig.json 中输入图像描述 在 "compilerOptions" "typeRoots": ["node_modules/@types", "src/anyNameYoulike.d.ts"]