为什么Array.prototype.includes(searchElement)的参数需要与数组元素相同的类型? [英] Why does the argument for Array.prototype.includes(searchElement) need the same type as array elements?
问题描述
老实说,我不知道我的设置是否有问题或这是否是打字稿功能.在下面的示例中:
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屋!