【问题标题】:Make javascript files aware of their typescript definition files让 javascript 文件知道它们的 typescript 定义文件
【发布时间】:2018-04-09 13:38:04
【问题描述】:

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 文件知道它们在 typescript 中的定义,最好不修改原始 javascript。

【问题讨论】:

  • 一般 .d.ts 文件仅用于为您无法控制的文件提供定义,例如外部模块的接口。您不能使用它为项目中的源代码创建并行定义。换句话说,在解释 JS 文件 (imported.js) 时,它忽略了定义。这真的不应该是要走的路。你应该有一个导入的.ts 文件并将其用于实现和定义。

标签: javascript typescript .d.ts


【解决方案1】:

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

将项目更改为:

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");

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

虽然这确实需要修改原始 javascript,但它只使用 cmets 来这样做。

限制

这并没有所有完整的 Typescript 类型检查的功能,但它的大部分功能都在那里。例如,如果您有一个返回对象的模块,其中包含键入的键:

/**
 * @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 返回一个数字,所以我们可以告诉 Typescript。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-04-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-04-06
    • 1970-01-01
    相关资源
    最近更新 更多