gpt4 book ai didi

javascript - 为什么 Array.prototype.includes(searchElement) 的参数需要与数组元素相同的类型?

转载 作者:行者123 更新时间:2023-12-01 15:52:50 26 4
gpt4 key购买 nike

老实说,我不知道我的设置是否有问题,或者这是否是 typescript 功能。在以下示例中:

type AllowedChars = 'x' | 'y' | 'z';
const exampleArr: AllowedChars[] = ['x', 'y', 'z'];

function checkKey(e: KeyboardEvent) {
if (exampleArr.includes(e.key)) { // <-- here
// ...
}
}

typescript 编译器提示 Argument of type 'string' is not assignable to parameter of type 'AllowedChars'.但是我在哪里分配? Array.prototype.includes返回一个 bool 值(我没有存储)。我可以通过类型断言来消除错误,如下所示:
if (exampleArr.includes(e.key as AllowedChars)) {}

但这怎么正确,我期待用户输入可能是任何东西。我不明白为什么用于检查是否在数组中找到元素的函数( Array.prototype.includes() )应该了解预期的输入类型。

我的 tsconfig.json ( typescript v3.1.3):
 {
"compilerOptions": {
"target": "esnext",
"moduleResolution": "node",
"allowJs": true,
"noEmit": true,
"strict": true,
"isolatedModules": true,
"esModuleInterop": true,
"jsx": "preserve",
},
"include": [
"src"
],
"exclude": [
"node_modules",
"**/__tests__/**"
]
}

任何帮助,将不胜感激!

最佳答案

microsoft/TypeScript#26255完整讨论 Array.prototype.includes()和父类(super class)型。

是的,从技术上讲,允许 searchElement 应该是安全的。 Array<T>.includes() 中的参数成为 T 的父类(super class)型,但 standard TypeScript library declaration假设它只是 T .对于大多数目的,这是一个很好的假设,因为您通常不想像@GustavoLopes 提到的那样比较完全不相关的类型。但你的类型并非完全不相关,是吗?
有不同的方法来处理这个问题。您所做的断言可能是最不正确的,因为您断言 stringAllowedChars即使它可能不是。它“完成了工作”,但你对此感到不安是对的。

另一种方法是通过declaration merging 本地覆盖标准库。接受父类(super class)型,这有点复杂,因为 TypeScript 不支持父类(super class)型约束(请参阅 ms/TS#14520 以获得功能请求)。相反,声明使用 conditional types模拟父类(super class)型约束:

// remove "declare global" if you are writing your code in global scope to begin with
declare global {
interface Array<T> {
includes<U extends (T extends U ? unknown : never)>(
searchElement: U, fromIndex?: number): boolean;
}
}
然后您的原始代码将正常工作:
if (exampleArr.includes(e.key)) {} // okay
// call to includes inspects as
// (method) Array<AllowedChars>.includes<string>(
// searchElement: string, fromIndex?: number | undefined): boolean (+1 overload)
同时仍然防止比较完全不相关的类型:
if (exampleArr.includes(123)) {} // error
// Argument of type '123' is not assignable to parameter of type 'AllowedChars'.

但处理这个问题的最简单且仍然正确的方法是扩大 exampleArr 的类型。至 readonly string[] :
const stringArr: readonly string[] = exampleArr; // no assertion
if (stringArr.includes(e.key)) {} // okay
或者更简洁地像:
if ((exampleArr as readonly string[]).includes(e.key)) {} // okay
扩大至 readonly string[]很好,但要小心扩大到 string[] ,这有点危险,因为 TypeScript 不安全地对待 Array<T>作为 covariantT为了方便。这很适合阅读,但是当您编写属性时会遇到问题:
(exampleArr as string[]).push("whoopsie"); // uh oh, don't do this
但是由于您只是从数组中读取它是非常安全的,为什么 readonly被推荐。

Playground link to code

关于javascript - 为什么 Array.prototype.includes(searchElement) 的参数需要与数组元素相同的类型?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53033854/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com