Аргументы одинаковой длины Typescript

Я хотел бы написать функцию в Typescript следующим образом

x, y => void

Где x — массив типа string[], а y — массив типа string[][], но я хотел бы ограничить y, чтобы внутренние массивы имели ту же длину, что и массив x.

Это возможно?

Зод: сила проверки и преобразования данных
Зод: сила проверки и преобразования данных
Сегодня я хочу познакомить вас с библиотекой Zod и раскрыть некоторые ее особенности, например, возможности валидации и трансформации данных, а также...
Как заставить Remix работать с Mantine и Cloudflare Pages/Workers
Как заставить Remix работать с Mantine и Cloudflare Pages/Workers
Мне нравится библиотека Mantine Component , но заставить ее работать без проблем с Remix бывает непросто.
Угловой продивер
Угловой продивер
Оригинал этой статьи на турецком языке. ChatGPT используется только для перевода на английский язык.
TypeScript против JavaScript
TypeScript против JavaScript
TypeScript vs JavaScript - в чем различия и какой из них выбрать?
Синхронизация localStorage в масштабах всего приложения с помощью пользовательского реактивного хука useLocalStorage
Синхронизация localStorage в масштабах всего приложения с помощью пользовательского реактивного хука useLocalStorage
Не все нужно хранить на стороне сервера. Иногда все, что вам нужно, это постоянное хранилище на стороне клиента для хранения уникальных для клиента...
Что такое ленивая загрузка в Angular и как ее применять
Что такое ленивая загрузка в Angular и как ее применять
Ленивая загрузка - это техника, используемая в Angular для повышения производительности приложения путем загрузки модулей только тогда, когда они...
2
0
631
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

ОБНОВЛЕНИЕ 2022 Это можно сделать гораздо проще и менее многословно:



function array<X extends unknown[], Y extends X[]>(x: [...X], y: [...Y]) {
    return [1, 2, 3] as any
}

const result = array([1, 2, 3], [[1, 1, 1]]) // ok

const result2 = array([1, 2, 3], [[1, 1, 1], [1, 1]]) // expected error

const result3 = array([1, 2, 3], [[1, 1, 1], [1]]) // expected error

const result4 = array([1, 2], [[1, 1], [1, 1]]) // ok

const result5 = array([1, 2], [[1, 1], [1]]) // expected error

Я просто не знал о типах вариативных кортежей 1 год назад: D

Да, это возможно.

СЧИТАЙТЕ ЭТО РЕШЕНИЕ КАК УСТАРЕВШИМ

Вот мое решение:

/**
 * Second approach, is more advanced and it is exactly what you are looking for
 */
type ArrayElement = number
type Array1D = ReadonlyArray<ArrayElement>
type Array2D = ReadonlyArray<Array1D>

type MutableLength = unknown[]['length'] // number

/**
 * Get length of the array
 * Allow only immutable arrays
 */
export type Length<T extends ReadonlyArray<any>> = T extends { length: infer L } ? MutableLength extends L ? MutableLength : L : MutableLength;

/**
 * Compare length of the arrays
 */
type CompareLength<X extends ReadonlyArray<any>, Y extends ReadonlyArray<any>> =
    MutableLength extends Length<X> ? false : MutableLength extends Length<Y> ? false : Length<X> extends Length<Y> ? true : false;

/**
 * Check if all arrays (union type) have same length as X
 */
type Filter<X extends ReadonlyArray<any>, Y extends ReadonlyArray<any>> =
    X['length'] extends Y['length']
    ? Y['length'] extends X['length'] ? Y : never : never
{

    /**
     * CompareLength, compares length of X and filtered Y, 
     * if true - return zero index element - ReadonlyArray<ArrayElement>
     * if false - return never
     * 
     * So, if it will return never, then you can't pass second argument,
     * but if you did not provide second argument, you will receive another error - 
     * function expects two arguments
     */
    function array<X extends Array1D, Y extends {
        0: readonly ArrayElement[]
    }[CompareLength<X, Filter<X, Y>> extends true ? 0 : never]>(x: X, y: readonly Y[]): 'put here your returned type'

    function array<X extends Array1D, Y extends readonly ArrayElement[], Z extends CompareLength<X, Y>>(x: X, y: readonly Y[]) {
        return [1, 2, 3] as any
    }
    const result = array([1, 2, 3] as const, [[1, 1, 1], [1, 2, 3]] as const) // ok
    const result0 = array([1, 2, 3] as const, [[1, 1, 1]] as const) // ok

    const arr = [1, 2, 3] as const

    const result1 = array([1, 2, 3], [[1, 1, 1], [1]]) // error
    const result2 = array([1, 2, 3] as const, [[1, 1, 1], [1, 2]] as const) // error
    const result3 = array([1, 2, 3] as const, [[1, 2]] as const) // error
    const result4 = array([1, 2, 3] as const, [[1], [1, 2], [1, 2, 3]] as const) // error

    const result5 = array([1, 2, 3] as const, [1] as const) // error
    const result6 = array([1, 2, 3] as const, [[1, 2, 3], []] as const) // error
    const result7 = array(arr, [[1, 1, 1]]) // error, because TS is unable to fidure out length of mutable array. 
}

Я использовал number вместо string, потому что проще вводить числа, а не строки.

Смело меняйте ArrayElement на string

Пожалуйста, имейте в виду, что вы должны использовать каждый раз as const для определения длины массива.

Детская площадка

Другие вопросы по теме