3

I have a function that takes an arbitrary number of classes.

function findObjects(...Classes) { ... }

All classes inherit from one Component class. This function in a certain way searches for objects that are instances of these classes.

How to implement a template for functions with a variable number of parameters?

It should be something like this:

function findObjects(...Classes): [...Classes] { ... }

This is necessary for the correct definition of types and for the correct operation of intellisense.

3 Answers 3

2

You may want to have a look at tuple rest parameters, which are used to emulate functions with a variable number of parameters. A possible solution:

// We pass in a tuple of classes. This tuple is generically typed (type parameter T)
// { new(...arg: any): any } is constructor function type for a class
function findObjects<T extends { new(...arg: any): any }[]>(...cls: T): Partial<T> {
  // search for objects that are instances of these classes; return filtered classes
}

class Component { c = "c" }
class A extends Component { a = "a" }
class B extends Component { b = "b" }

const res = findObjects(A, B) // [(typeof A | undefined)?, (typeof B | undefined)?]

For the return type I used Partial<T>, which is a mapped tuple with optional elements of the passed in classes. It contains undefined at an index, if the corresponding class item is filtered out by your findObjects implementation (adjust the return type like you need it).

Playground

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

2 Comments

Thanks! Tell me how to write it in jsdoc? Tried like this: @param {T extends { new(...arg: any): any }[]} Classes @returns {Partial<T>} @template T. But return type is not displayed correctly.
@pank Hm, I actually never used JSDoc with TypeScript. According to here, it seems to be possible to add a type constraint for T in the template. Something like: @template {{ new(...arg: any): any }[]} T @param {T} cls @returns {Partial<T>}
1

My answer follows what you have written:

All classes inherit from one Component class. This function in a certain way searches for objects that are instances of these classes.

So in the solution I am using some base class Component and to search for some subclass members SubComponent.

// some empty classes
class Component {}
class SubComponent extends Component {}

function findObjects(...args: Component[]): SubComponent[] { 
  return args.filter(el => el instanceof SubComponent); // do some by instanceof for example
}
// using
const results = findObjects(new Component(), new Component(), new SubComponent());
// results is an array only with SubComponent element

The definition of the function is following - findObjects(...args: Component[]): SubComponent[].

  • ...args: Component[] - we take as arguments unknown number of Component instances
  • : SubComponent[] - we return array of SubComponents

I would propose to change little bit definition of this, as we return array, then better would be to take also array:

function findObjects(arr: Component[]): SubComponent[] { 
  return arr.filter(el => el instanceof SubComponent); // do some instanceof for example
}
// using
const results = findObjects([new Component(), new Component(), new SubComponent()]);
// results is an array only with SubComponent element

Pay attention that now the argument is one - arr but it is consistent with the output, we put array in, and take array out. Just a suggestion though.

Comments

1

You can use rest parameters as described in the docs

interface A { }

class B implements A { }


class C implements A { }


function findObjects(...objs: A[]): A[] {
  // function body

}

const obj1: B = {}
const obj2: C = {}

const result1 = findObjects(obj1);
const result2 = findObjects(obj1, obj2);

Hope that helps!

2 Comments

[A] means you get 1 element tuple not an array. Correct type is A[]
Thanks Maciej! Corrected

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.