6

I want to write a function which accepts a class as an argument, but only classes which implement a specific interface.

I know that I can use any, but it would be nice to rely on the type system to enforce this.

Some pseudocode to express what I mean...

interface MyInterface { ... }
class Class1 implements MyInterface { ... }
class Class2 { ... }

function doStuff(classParameter: Class implements MyInterface) { ... }
doStuff(Class1); // OK
doStuff(Class2); // Error

2 Answers 2

13

You can use a constructor signature to enforce the fact that the constructor will return an instance compatible with the interface. You can use it either as a generic parameter constraint or directly as a parameter depending on what you need to do with the class:

interface MyInterface { foo: number }
class Class1 implements MyInterface { foo: number }
class Class2 { bar: number }

function doStuff0(classParameter: new (...args: any[]) => MyInterface) { }
doStuff0(Class1); // OK
doStuff0(Class2); // Error

function doStuff1<T  extends new (...args: any[]) => MyInterface>(classParameter: T) {  }
doStuff1(Class1); // OK
doStuff1(Class2); // Error

Note I added members to the example, don't forget Typescript uses a structural type system, so compatibility is determined by members not by implements MyInterface declaration, so any class would be compatible if MyInterface were empty, and a class would be compatible if it had a foo member even if it didn't explicitly declare implements MyInterface

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

2 Comments

The second, generic example worked for me in the function signature, and I was able to use new(...) => MyInterface directly as a type in places where I referenced the class that was accepted as a function argument. Thanks!
Wouldn't class Class2 { foo: number } still pass the test ?
3

Maybe you can use generics to achieve what you want to do. Here's a workaround :

function doStuff<T extends myInterface>(classParameter: T) {
  ...
}

So here, T is a dynamic type which necessary implements myInterface (yeah, keyword extends while talking about interfaces is strange here).

You can check the documentation below, part "Generic constraints" https://www.typescriptlang.org/docs/handbook/generics.html

4 Comments

The question is not about how to accept a parameter that implements MyInterface (which would be answered with just function doStuff(x: MyInterface)), but about how to refer to the type of a constructor that produces a MyInterface. See @TitialCernicova-Dragomir's answer.
Hum, maybe I really don't get it, but it's not what I understand from Sophie's question... From the question : "I want to write a function which accepts a class as an argument, but only classes which implement a specific interface." Use generics really do the job, less rough than creating multiple constructors, for me. But ok, wait & see
She is passing the class to the function not an instance of it, ie doStuff(Class1) not doStuff(new Class1()). This could be a mistake, but I don't think so, she wants to pass in the class
Oh, I get it, indeed, I didn't understand the question. My bad :)

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.