相同长度的参数 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 来推断数组长度
操场
