我有一个MyArray类型的数组。
type Maybe<T> = T | null;
type MyArray = Maybe<Materials>[] | Maybe<Seasons>[] | Seasons[] | Materials[] | null | undefined;
type Value = Seasons | Materials;
示例代码:
if (!myArray?.length) {
return;
}
const isValid = myArray.includes(value); // typescript is complaining about value
问题是当我高亮value:
Argument of type Seasons | Materials is not assignable to parameter of type 'never'.
我怎样才能消除这个错误?
这个错误实际上是合法的,存在不匹配,因为:
- 一方面我们有一个
Seasons | Materials
(值) - 另一方面我们有(数组):
- 一个不接受该值的
Seasons[]
盒子,因为它可能是一个Materials
- 或者一盒不接受该值的
Materials[]
,因为它可能是一个Seasons
- 一个不接受该值的
我们可以尝试使用一个中间的includes
函数来修复它,例如:
type ElementOf<A extends any[], B> = B extends A[number] ? B : never
function includes<A extends any[], B>(list: A, element: ElementOf<A, B>): boolean {
return list.includes(element)
}
这个函数确保:
- 在语义上,我们要么保留一个
Seasons[]
的盒子,要么保留一个Materials[]
的盒子,但是不是一盒(Seasons | Materials)[]
- 第一个参数必须使用数组
- 必须使用的值的类型可能包含在第一个参数 的数组中
const isValid = includes(myArray, value)
你可以在这个操场上看看。
之前答:
我很确定我们可以通过简化MyArray
类型的定义来解决这个问题:
type MyArray = Maybe<Array<Maybe<Materials> | Maybe<Seasons>>> | undefined
// or: type MyArray = Array<Maybe<Materials> | Maybe<Seasons>> | null | undefined
function foo(myArray: MyArray, value: Value): void {
// myArray: Maybe<Array<Value | null>> | undefined (or, equivalent -> myArray: Array<Value | null> | null | undefined)
if (!myArray?.length) {
return
}
// myArray: Array<Value | null>
const isValid = myArray.includes(value)
console.log(isValid)
}
当myArray
的类型是数组的联合类型时:
type MyArray =
| Maybe<Materials>[]
| Maybe<Seasons>[]
| null
| undefined
代替联合类型的数组:
type MyArray = Array<Maybe<Materials> | Maybe<Seasons>> | null | undefined
那么使用includes
函数时的类型推断就被打破了,所以我们最终得到的类型是never
而不是Maybe<Value>
(或Value | null
,同样的事情)。
我不知道这个行为是故意的还是一个bug,如果在TypeScript存储库中找到一个提到这个的开放问题,或者创建一个新的问题,可能会很有趣。
(游乐场)