简体   繁体   中英

Definitely assigned for destructuring with nouncheckedindexedaccess

With noUncheckedUndexedAccess , being explicit with array indexes is necessary:

const someArray: number[] = [];
const value = someArray[0]!; // i have to say "i know what i am doing"

However, for destructuring, i couldn't find a simple way to do so:

const execResult = /a(.)(.)/.exec('axy');
if (execResult === null) throw new Error('Regex should match');
const [, first, second] = execResult; // each get `string | undefined`

Is there any similar short way to remove undefined from the types here? I can type-cast the right side, but that is both unsafe, and i need to write out the entire type again. In this case, it's completely clear, that the elements exist, as the regex has two capturing groups.

One possibility would be a generic helper-function, which does the cast:

type NonNullTupleFromArrayHead<T extends readonly any[], U extends readonly any[] = []> =
  number extends T['length']
    ? U['length'] extends 64
      ? U
      // Needs TS 4.5 TCO
      : NonNullTupleFromArrayHead<T, [...U, NonNullable<T[U['length']]>]>
    : { [K in keyof T]: NonNullable<T[K]> }; // make length match for tuples

const assertNonNullHead =
  <T extends readonly any[]>(x: T) => x as T & NonNullTupleFromArrayHead<T>;

const execResult = /a(.)(.)/.exec('axy');
if (execResult === null) throw new Error('Regex should match');
const [, first, second] = assertNonNullHead(execResult);

// Some other use cases
const t1 = [1, 'str', { a: 0 }] as const;
declare const t2: [1 | null, 'str' | undefined, { a: 0 }];
declare const t3: (string | number | undefined | null)[];
declare const t4: [number | null, number | undefined, ...(string | undefined)[]];

const [a1, b1, c1] = assertNonNullHead(t1); // 1, 'str', { readonly a: 0 }
const [a2, b2, c2] = assertNonNullHead(t2)  // 1, 'str', { a: 0 }
const [a3, b3]     = assertNonNullHead(t3)  // string | number, string | number
const [a4, b4, c4] = assertNonNullHead(t4)  // number, number, string

This is slightly more verbose than a non-null-assertion-operator ! , but not by much. While hard-coding limits is usually bad practice, i cannot think of a case, where destructuring more than 64 elements in one statement is ever a good idea to begin with.

Note, that identity functions are, for hot code, typically completely erased by modern engines' function inliners. Therefore, performance differences compared to an even more verbose cast ( execResult as typeof execResult & NonNullTupleFromArrayHead<typeof execResult> ) are not really a concern.

Better solutions, and optimizations for this one, are welcome.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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