为什么Array.prototype.includes(searchElement)的参数需要与数组元素相同的类型? [英] Why does the argument for Array.prototype.includes(searchElement) need the same type as array elements?

查看:36
本文介绍了为什么Array.prototype.includes(searchElement)的参数需要与数组元素相同的类型?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

老实说,我不知道我的设置是否有问题或这是否是打字稿功能.在下面的示例中:

I honestly don't know if something is wrong with my settings or of if this is a typescript feature. In the following example:

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

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

打字稿编译器抱怨说类型'string'的参数不能分配给'AllowedChars'类型的参数.但是我应该在哪里分配呢? Array.prototype.includes 返回一个布尔值(我没有存储).我可以通过类型断言来使错误保持沉默,如下所示:

The typescript compiler complains that Argument of type 'string' is not assignable to parameter of type 'AllowedChars'. But where am I assigning? Array.prototype.includes returns a boolean (which I am not storing). I could silence the error by a type assertion, like this:

if (exampleArr.includes(e.key as AllowedChars)) {}

但是这是正确的吗,我正在等待用户输入,该输入可以是任何东西.我不明白为什么检查数组中是否存在元素的函数( Array.prototype.includes())应该具有关于数组类型的知识期望的输入.

But how is that correct, I am expecing user input which could be anything. I don't understand why a function (Array.prototype.includes()) made to check if an element is found in an array, should have knowledge about the type of input to expect.

我的 tsconfig.json (打字稿v3.1.3):

My 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__/**"
    ]
  }

任何帮助将不胜感激!

推荐答案

是的,从技术上讲,允许在 Array< T> .includes()中使用 searchElement 参数应该是安全的.code>是 T 的超类型,但

Yes, technically it should be safe to allow the searchElement parameter in Array<T>.includes() to be a supertype of T, but the standard TypeScript library declaration assumes that it is just T. For most purposes, this is a good assumption, since you don't usually want to compare completely unrelated types as @GustavoLopes mentions. But your type isn't completely unrelated, is it?

有不同的处理方法.您所做的断言可能是最不正确的断言,因为您断言 string AllowedChars ,即使可能不是.它完成了工作",但是您对此感到不安是正确的.

There are different ways to deal with this. The assertion you've made is probably the least correct one because you are asserting that a string is an AllowedChars even though it might not be. It "gets the job done" but you're right to feel uneasy about it.

另一种方法是通过声明合并来在本地覆盖标准库接受超级类型,这有点复杂,并使用条件类型:

Another way is to locally override the standard library via declaration merging to accept supertypes, which is a bit complicated and uses conditional types:

// 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;
  }
}

然后您的原始代码就可以使用了:

Then your original code will just work:

if (exampleArr.includes(e.key)) {} // okay
// call to includes inspects as
// (method) Array<AllowedChars>.includes<string>(searchElement: string, fromIndex?: number | undefined): boolean (+1 overload)

同时仍然阻止比较完全不相关的类型:

while still preventing the comparison of completely unrelated types:

if (exampleArr.includes(123)) {} // error
// Argument of type '123' is not assignable to parameter of type 'AllowedChars'.


但是,最简单但仍正确的方法是将 exampleArr 的类型扩展为 string [] :

const stringArr: string[] = exampleArr; // no assertion
if (stringArr.includes(e.key)) {}  // okay

或更简洁地说:

if ((exampleArr as string[]).includes(e.key)) {} // okay

仅使用某种"正确的方法来绑定到 string [] ,因为TypeScript不安全地将 Array< T> 视为

Widening to string[] is only "kind of" correct because TypeScript unsafely treats Array<T> as covariant in T for convenience. This is fine for reading, but when you write properties you run into problems:

(exampleArr as string[]).push("whoopsie"); // uh oh

但是由于您只是从数组中读取数据,因此非常安全.

But since you're just reading from the array it's perfectly safe.

好的,希望其中之一能对您有所帮助.祝你好运!

Okay, hope one of those helps you. Good luck!

这篇关于为什么Array.prototype.includes(searchElement)的参数需要与数组元素相同的类型?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆