3

I need to define an interface for function parameters. Consider we have two parameters, both of type array and one is dependent on the other in terms of another one's length and containing elements' type(Elements are of the same type).

Is there a way to declare one of them as lengthy as another one?

3
  • 1
    Pleese see this article catchts.com/compare-arguments Could you please provide more examples ? Commented Mar 1, 2021 at 14:11
  • 1
    @captain-yossarian - It's important to disclose your affiliation when you link to your own blog. (It doesn't have to be a big thing, just "See my article here:" for instance.) Commented Mar 1, 2021 at 14:17
  • 1
    @T.J.Crowder thanks, nice catch. I will keep that in mind next time! Commented Mar 1, 2021 at 14:22

1 Answer 1

4

UPDATE January 30 2022

There is much easier and less verbose way to do it:

type Json =
  | null
  | string
  | boolean
  | number
  | { [prop: string]: Json }
  | Array<Json>

function array<
  Elem,
  First extends Elem[],
  >(x: [...First], y: [...First]) {

}

/**
 * Passed
 */
{
  const _ = array([1, 2, 3], [1, 1, 1]) // ok
  const __ = array(['a', 'b', 'c'], ['x', 'x', 'x']) // ok
}


/**
 * Failed
 */
{
  const __ = array([1, 2, 3], [1, 1, 1, 1]) //expected error
  const ___ = array([1, 2, 3], ['a', 'b', 'c']) //expected error
  const ____ = array([1], []) //expected error
  const _____ = array([], [1]) //expected error
}

Playground

Here you can find very similar answer

Here you can find more information about inference on function arguments

TOOO VERBOSE AND UNEFFECTIVE WAY

Here you have:

type ArrayElement = number;
type Array1D = ReadonlyArray<ArrayElement>;


type MutableLength = unknown[]["length"]; // number

export type Length<T extends ReadonlyArray<any>> = T extends { length: infer L }
  ? MutableLength extends L
    ? MutableLength
    : L
  : MutableLength;

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;

type CompareType<
  X extends ReadonlyArray<any>,
  Y extends ReadonlyArray<any>
> = X[number] extends Y[number] ? true:false

function array<
    X extends Array1D,
    Y extends {
        0: Array1D
    }[CompareLength<X,Y> extends true? CompareType<X,Y> extends true ?0 : never:never],
    >(x: X, y: Y) {

}
const result = array([1, 2, 3] as const, [1, 2, 3] as const) // ok
const result2 = array([1, 2, 3] as const, [1, 2, '3'] as const) // error
const result3 = array([1, 2, 3] as const, [1, 2] as const) // error
const result4 = array([1, 2, 3] as const, [] as const) // error
const result5 = array([1, 2, 3] as const, []) // error
const result6 = array([], []) // error, because arrays are mutable. TS is unable to find out the length

Playground

This is my article, here you can find more explanations

Please keep in mind, you should operate only on readonly arrays.

Sign up to request clarification or add additional context in comments.

3 Comments

I'm confused by your last sentence. Are you saying the solution only works for read-only arrays, or that in general the OP should only use read-only arrays, or both, or... ? :-)
@T.J.Crowder Yes and no ) For instance, if you use only mutable arrays, my solution will throw an error, because TS is unable to find out the length of mutable arrays. I added result6
@T.J.Crowder made an update, this solution works for all arrays, not only for readonly. Did not have much exp that days

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.