网站搜索

相同长度的参数 Typescript


我想用 Typescript 写一个函数,如下所示

x, y => void

其中 x 是类型为 string[] 的数组,y 是类型为 string[][] 的数组,但我想限制 y,使得内部数组 必须与数组 x 的长度相同。

这可能吗?

答案#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

我一年前根本不知道可变元组类型 :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 来推断数组长度

操场