【问题标题】:How to enforce stricter typing on Maps and Sets in TypeScript?如何在 TypeScript 中对 Maps 和 Sets 强制执行更严格的输入?
【发布时间】:2022-06-29 05:32:42
【问题描述】:

如果我像这样创建地图:(playground)

const x = new Map();
const y = x.get("foo");
y.thisDoesntExist();

我希望在最后一行出现错误(至少在严格模式下),因为我从未指定 new Map 的键和值类型应该是什么。相反,地图的类型是Map<any, any>,所以我没有收到任何警告。 Set<any> 也是如此。

我正在移植一个 JavaScript 项目,所以像这样的案例到处都是,很难判断哪里缺少类型。

有没有办法配置打字稿,以便在我尝试在没有泛型的情况下实例化 Sets 和 Maps 时向我发出警告?或者至少让泛型默认为Set<unknown>

【问题讨论】:

  • 我希望它在noImplicitAny 下发出警告,但似乎没有。 github.com/microsoft/TypeScript/issues/13609
  • @AlekseyL。啊谢谢!我觉得我一直在到处寻找这样的问题,但我找不到。
  • 我认为问题在于MapConstructor明确指定`n​​ew(): Map;`
  • 您可以使用声明合并并覆盖MapConstructor 接口。如果这对你有用,我可以添加一个答案。 typescriptlang.org/play?#code/…
  • 啊,是的,这就是我要找的东西!不幸的是,我认为我无法使用它。我主要在 JSDoc 中使用类型,我刚刚发现 JSDoc 不支持使用泛型调用构造函数:(github.com/microsoft/TypeScript/issues/38876

标签: typescript


【解决方案1】:

无参数 Map constructorMap<any, any> 返回类型:

interface MapConstructor {
    new(): Map<any, any>;
    // ...
}

因此 noImplicitAny 在这里没有帮助(类型是明确的?)

可以做的是用Map&lt;unknown, unknown&gt;覆盖它(declaration merging):

interface MapConstructor {
    new(): Map<unknown, unknown>;
}

现在y.thisDoesntExist();会报错。

Playground


Set 的行为不同,因为它的构造函数定义为:

new <T = any>(values?: readonly T[] | null): Set<T>;

所以如果没有提供泛型类型和值 - 类型将是 unknown:

const s = new Set(); // s: Set<unknown>

【讨论】:

  • 通过一些更改,我设法让它也适用于 jsdoc :)
  • 谢谢,不知道 JS 有不同的默认值
  • 是的,我也没有,因为这个才知道的。
【解决方案2】:

更新(2022 年 6 月 28 日)

在使用 JavaScript + JSDoc 时,似乎简单地使用 never 而不是 unknown 就足以使类型变得严格。不知道为什么我之前必须跳过这么多圈,但现在我只是在使用。

interface SetConstructor {
    new(): Set<never>;
}

interface MapConstructor {
    new(): Map<never, never>;
}

旧答案

要使用 JSDoc 在 js 中使用 ts,您可以在新的 .d.ts 中添加以下内容

interface MapConstructor extends Omit<MapConstructor, 'new'> {
    new<K = unknown, V = unknown>(entries?: readonly (readonly [K, V])[] | null): Map<K, V>;
}

interface SetConstructor {
    new <T = unknown>(values?: readonly T[] | null): Set<T>;
}

在 JavaScript 中,泛型在未设置时默认为 any (#14907),因此您必须明确将其默认设置为 unknown。因此,在使用 JavaScript 时,空的构造函数不起作用。

MapConstructorlib.es2015.collection.d.ts 中有一个空的new(): Map&lt;any, any&gt; 条目。因此,为了删除它,我们使用Omit&lt;MapConstructor, 'new'&gt;。然后我们可以指定已经存在的相同构造函数,除了显式 unknown 作为默认值。

SetConstructor 没有空的 new() 条目,但它确实有 new &lt;T = any&gt;,所以我们也必须用 unknown 覆盖它。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-05-26
    • 2012-05-15
    • 1970-01-01
    • 2014-06-11
    • 1970-01-01
    • 2022-01-11
    • 1970-01-01
    • 2015-11-12
    相关资源
    最近更新 更多