使 javascript 个文件知道它们的打字稿定义文件

Make javascript files aware of their typescript definition files

Typescript 允许您为本地 javascript 文件编写 .d.ts 定义文件,如下所示:

src/
  main.js
  imported.js
  imported.d.ts

main.js

import { func } from './imported';
console.log(func("1", "1"));

imported.js

export const func = (numVal, strVal) =>
  `The number is ${numVal}, the string is ${strVal}`;

imported.d.ts

export const func: (numVal: number, strVal: string) => string;

这给出了以下错误,选项noImplicitAny:

src/imported.js(1,22): error TS7006: Parameter 'numVal' implicitly has an 'any' type.
src/imported.js(1,30): error TS7006: Parameter 'strVal' implicitly has an 'any' type.
src/main.js(3,18): error TS2345: Argument of type '"1"' is not assignable to parameter of type 'number'.

最后一个错误很好,它阻止我们在本应传递数字作为第一个参数时传递字符串。但是对于前两个,在导入的 javascript 文件中,它并不知道参数的类型已经定义。这会阻止您使用 noImplicitAny,但也会阻止您在例如将 numValue 传递给需要字符串的函数时出错。

是否可以让 javascript 文件知道它们在打字稿中的定义,最好不要修改原始 javascript。

虽然 javascript 文件无法识别其定义文件,但 Typescript 2.3 添加了对使用 JSDoc 注释进行类型检查的支持。

将项目更改为:

src/
  main.js
  imported.js

imported.js

/**
 * @return {string} 
 * @param {number} numVal 
 * @param {string} strVal 
 */
export const func = (numVal, strVal) =>
  `The number is ${funcs.func3(numVal)}, the string is ${strVal}`;

main.js

import { func } from './imported';

/**
 * Works fine
 * @param {number} number 
 */
const mainFunc1 = (number) =>
  func(number, "Hello");      

/**
 * Argument of type 'string' is not assignable to parameter of type 'number'
 * @param {string} string 
 */
const mainFunc2 = (string) =>
  func(string, "Hello");

现在 typescript 编译器知道 numVal 是一个数字,而 strVal 是一个字符串。尝试将 numVal 传递给不接受数字的函数会导致错误。 func 中的 @return 在这里在技术上是多余的,因为它知道它正在返回字符串(即使没有 JSDoc 也会知道),但它有利于保持一致性。

虽然这确实需要修改原始 javascript,但它仅使用注释来完成。

限制

它没有所有 完整 Typescript 类型检查的功能,但它已经具备了大部分功能。例如,如果您有一个 returns 对象的模块,包含键入的键:

/**
 * @param {number} num 
 */
const func1 = (num) => num * 2;

export default {
  func1,
}

然后使用它:

import imported from './module';

imported.func1(3);    // This is okay
imported.func1("3");  // This is an error
imported.func2(3);    // This is also okay, but it shouldn't be

对于 javascript 文件,这不会出错,因为它没有为默认导出生成类型,因此无法确认 func2 不存在。而在 Typescript 中,它会告诉您 Property 'func2' does not exist on type '{ func: (num: number) => number; }'. Did you mean 'func'?,而无需显式声明默认导出的类型。

打字稿 2.5

Typescript 2.5 还添加了对 JSDoc 类型断言的支持,例如:

// Argument of type 'string | number' is not assignable to parameter of type 'number'.
const func1 = () =>
  func(funcReturnsNumberOrString(true), "Hi");

// Fine
const func2 = () =>
  func(/** @type {number} */ (funcReturnsNumberOrString(true)), "Hi");

/**
 * @returns { number | string }
 * @param {boolean} bool
 */
const funcReturnsNumberOrString = (bool) =>
  bool ? 2 : "2";

在这种情况下,我们知道 funcReturnsNumberOrString returns 是一个数字,因此我们可以这样告诉 Typescript。