简体   繁体   English

数组解构赋值中的 noUncheckedIndexedAccess 类型断言

[英]noUncheckedIndexedAccess type assertion in array destructuring assignment

With noUncheckedIndexedAccess , array accesses now return T | undefined使用noUncheckedIndexedAccess ,数组访问现在返回T | undefined T | undefined to reflect the fact that you might be accessing past .length . T | undefined以反映您可能正在访问过去的事实.length Sometimes you know you aren't and can use a !有时您知道自己不是并且可以使用! type assertion to tell TypeScript to forget about it.输入断言告诉 TypeScript 忘记它。

But I can't figure out how to do that in this case:但我不知道在这种情况下如何做到这一点:

function double(x: number[]): number[] {
  return x.map(a => a * 2)
}

function foo() {
  let a: number = 5;
  let b: number = 6;
  [a, b] = double([b, a]);
}

My first guess is我的第一个猜测是

  [a!, b!] = double([b, a]);

But it doesn't work.但它不起作用。 Is there a non-tedious way to do this?有没有一种不乏味的方法来做到这一点?

Playground Link 游乐场链接

This is a shortcoming of how the map method is defined on the ReadonlyArray interface in the standard library (and the ReadonlyArray interface in general): it returns a mutable array regardless of whether the input type was a tuple or not:这是map方法在标准库中的ReadonlyArray接口(以及一般的ReadonlyArray接口)上定义的一个缺点:无论输入类型是否为元组,它都会返回一个可变数组:

interface ReadonlyArray<T> {
  map<U>(callbackfn: (value: T, index: number, array: readonly T[]) => U, thisArg?: any): U[]
}

Since the type of values in the ReadonlyArray is determined by a generic type parameter T , there is no way to determine an exact relationship between indices and values which is essential to being able to return a tuple.由于ReadonlyArray中值的类型由泛型类型参数T确定,因此无法确定索引和值之间的确切关系,这对于能够返回元组至关重要。

An inherently unsafe, but easy way out using type assertions with as was already provided (nothing wrong with it per se since your situation is exactly the case where you know more than the compiler does).一种本质上不安全但很简单的方法是使用带有as类型断言(它本身没有问题,因为您的情况正是您比编译器了解更多的情况)。

Another, safer, but tedious solution you are likely to be aware of is defining your variables as number | undefined您可能知道的另一个更安全但乏味的解决方案是将变量定义为number | undefined number | undefined (a little less tedious if you define a helper MaybeNum or similar) and then use type guards to reassure the compiler. number | undefined (如果你定义了一个助手MaybeNum或类似的,那么乏味一点),然后使用类型保护来让编译器放心。

Finally, you can take advantage of the declaration merging technique and provide your own overload for the map method that will use this inference to get the tuple type.最后,您可以利用声明合并技术并为map方法提供您自己的重载,该方法将使用this推断来获取元组类型。 With it, you can return a mapped type in which values are replaced by the inferred U :有了它,您可以返回一个映射类型,其中值被推断的U替换:

interface ReadonlyArray<T> {
  map<U>(callbackfn: (value: T, index: number, array: readonly T[]) => U, thisArg?: any): { [ P in keyof this ] : U };
}

Your double function now only needs a tweak to tell the compiler that x is going to be a readonly array:你的double function 现在只需要一个调整来告诉编译器x将是一个readonly数组:

const dbl = <T extends readonly number[]>(x: T) => x.map(a => a * 2);

The result is exactly what you want (obviously, an as const required when you pass an array literal so as it is treated as a tuple, but this is a small price to pay), what's more, the ReadonlyArray methods can still be used properly:结果正是您想要的(显然,当您传递数组文字时需要as const ,因此它被视为元组,但这是一个很小的代价),更重要的是, ReadonlyArray方法仍然可以正确使用:

function foo2() {
  let a: number = 5;
  let b: number = 6;
  [a, b] = dbl([b, a] as const); //OK
}

dbl([5,6] as const).forEach((a) => console.log(a)); //OK, a is number here

Playground 操场

Maybe just cast it to a tuple?也许只是将其转换为元组?

function double(x: number[]): number[] {
  return x.map(a => a * 2)
}

function foo() {
  let a: number = 5;
  let b: number = 6;
  [a, b] = double([b, a]) as [number, number];
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM