【问题标题】:noUncheckedIndexedAccess type assertion in array destructuring assignment数组解构赋值中的 noUncheckedIndexedAccess 类型断言
【发布时间】:2021-03-03 14:28:44
【问题描述】:

使用noUncheckedIndexedAccess,数组访问现在返回T | undefined,以反映您可能访问过去.length 的事实。有时你知道你不是并且可以使用 ! 类型断言来告诉 TypeScript 忘记它。

但我不知道在这种情况下如何做到这一点:

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]);
}

我的第一个猜测是

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

但它不起作用。有没有一种不乏味的方法来做到这一点?

Playground Link

【问题讨论】:

    标签: typescript tuples


    【解决方案1】:

    这是在标准库的ReadonlyArray 接口(以及一般的ReadonlyArray 接口)上定义map 方法的一个缺点:无论输入类型是否为元组与否:

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

    由于ReadonlyArray 中的值类型由泛型类型参数T 确定,因此无法确定索引和值之间的确切关系,这对于能够返回元组至关重要。

    使用带有as 的类型断言的一个本质上不安全但简单的方法是already provided(它本身并没有错,因为您的情况正是您比编译器知道的更多的情况)。

    您可能知道的另一个更安全但繁琐的解决方案是将您的变量定义为number | undefined(如果您定义了一个帮助器MaybeNum 或类似的东西,那么繁琐一点),然后使用类型保护来让编译器放心.

    最后,您可以利用声明合并技术并为map 方法提供您自己的重载,该方法将使用this 推断来获取元组类型。使用它,您可以返回一个映射类型,其中值被推断的U 替换:

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

    您的 double 函数现在只需要调整即可告诉编译器 x 将成为 readonly 数组:

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

    结果正是您想要的(显然,当您传递数组文字时需要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

    【讨论】:

      【解决方案2】:

      也许只是将它转换为一个元组?

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

      【讨论】:

        猜你喜欢
        • 2020-10-30
        • 2021-08-08
        • 1970-01-01
        • 2020-03-13
        • 2018-06-08
        • 2016-12-13
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多