Interface Defining a Constructor Signature

Interface defining a constructor signature?

As already well noted, you can't have constructors on an Interface. But since this is such a highly ranked result in Google some 7 years later, I thought I would chip in here - specifically to show how you could use an abstract base class in tandem with your existing Interface and maybe cut down on the amount of refactoring needed in the future for similar situations. This concept has already been hinted at in some of the comments but I thought it would be worth showing how to actually do it.

So you have your main interface that looks like this so far:

public interface IDrawable
{
void Update();
void Draw();
}

Now create an abstract class with the constructor you want to enforce. Actually, since it's now available since the time you wrote your original question, we can get a little fancy here and use generics in this situation so that we can adapt this to other interfaces that might need the same functionality but have different constructor requirements:

public abstract class MustInitialize<T>
{
public MustInitialize(T parameters)
{

}
}

Now you'll need to create a new class that inherits from both the IDrawable interface and the MustInitialize abstract class:

public class Drawable : MustInitialize<GraphicsDeviceManager>, IDrawable
{
GraphicsDeviceManager _graphicsDeviceManager;

public Drawable(GraphicsDeviceManager graphicsDeviceManager)
: base (graphicsDeviceManager)
{
_graphicsDeviceManager = graphicsDeviceManager;
}

public void Update()
{
//use _graphicsDeviceManager here to do whatever
}

public void Draw()
{
//use _graphicsDeviceManager here to do whatever
}
}

Then just create an instance of Drawable and you're good to go:

IDrawable drawableService = new Drawable(myGraphicsDeviceManager);

The cool thing here is that the new Drawable class we created still behaves just like what we would expect from an IDrawable.

If you need to pass more than one parameter to the MustInitialize constructor, you can create a class that defines properties for all of the fields you'll need to pass in.

Constructor in an Interface?

Taking some of the things you have described:

"So you could be sure that some fields in a class are defined for
every implementation of this interface."

"If a define a Interface for this class so that I can have more
classes which implement the message interface, I can only define the
send method and not the constructor"

...these requirements are exactly what abstract classes are for.

constructor in typescript interface

Where is this library from? Whoever wrote it deserves a stern talking-to. Either it's a mistake (in which case they never tested it) or it's intentional but eeeeevil: using the not-quite-reserved word constructor as an identifier for an instance method is just asking for trouble.

EDIT 2019-04-25: The trouble is worse than just "this is a bad idea"; it actually looks like once JavaScript natively supports class fields, it is going to be an error to have a class with a property named "constructor". TypeScript will change to reflect this in version 3.5+, so the implementation below will stop working then. See recently opened GitHub issue Microsoft/TypeScript#31020 for more information. After TS3.5 it looks like there will be no way to have a class with an instance constructor property that is not the actual constructor function itself.

Either the library author intended to refer to a real constructor that you call with new, in which case they should do something like @Series0ne's suggestion; or the author really wants to use an instance method to initialize the object, in which case they should do everyone a favor and use a more conventional method name like init().

In either case nobody should accept the interface you've been given, and certainly nobody should implement it.

Let's implement it:

export class LatLngImpl implements LatLng {
private _lat: number;
private _lng: number;
lat() {
return this._lat;
}
lng() {
return this._lng;
}
// here's the important part, but see Microsoft/TypeScript#31020
"constructor"(lat: number, lng: number) {
this._lat = lat;
this._lng = lng;
}
}

The trick is to use the string literal "constructor" instead of the bare word constructor. From the TypeScript spec:

String literals may be used to give properties names that are not valid identifiers

By using the string literal, we were able to declare it as an instance method, and not the static class constructor method that is invoked when you call new, and it compiles happily.

Now we can use it, if we dare:

const latLng = new LatLngImpl();
latLng.constructor(47.6391132, -122.1284311); // Why not init()?
console.log("Latitude: " + latLng.lat() + ", Longitude: " + latLng.lng());

Yuck, we shouldn't have dared.

EDIT AGAIN 2019-04-25 The above quoted-string implementation will not work starting in TypeScript 3.5, and the correct answer to this will be "you can't do this" and "use a real constructor instead".

Hope that helps; good luck!

Typescript - Is it possible to have interface defining a constructor with generics?

Constructor signatures in interfaces are not implementable in classes. This is by design. From the documentation:

When working with classes and interfaces, it helps to keep in mind
that a class has two types: the type of the static side and the type
of the instance side. You may notice that if you create an interface
with a construct signature and try to create a class that implements
this interface you get an error:

interface ClockConstructor {
new (hour: number, minute: number);
}

class Clock implements ClockConstructor {
currentTime: Date;
constructor(h: number, m: number) { }
}

This is because when a class implements an interface, only the
instance side of the class is checked. Since the constructor sits in
the static side, it is not included in this check.

Instead, you would need to work with the static side of the class
directly. In this example, we define two interfaces, ClockConstructor
for the constructor and ClockInterface for the instance methods. Then
for convenience we define a constructor function createClock that
creates instances of the type that is passed to it.

interface ClockConstructor {
new (hour: number, minute: number): ClockInterface;
}
interface ClockInterface {
tick();
}

function createClock(ctor: ClockConstructor, hour: number, minute: number): ClockInterface {
return new ctor(hour, minute);
}

class DigitalClock implements ClockInterface {
constructor(h: number, m: number) { }
tick() {
console.log("beep beep");
}
}
class AnalogClock implements ClockInterface {
constructor(h: number, m: number) { }
tick() {
console.log("tick tock");
}
}

let digital = createClock(DigitalClock, 12, 17); let analog =
createClock(AnalogClock, 7, 32);

Because createClock’s first parameter
is of type ClockConstructor, in createClock(AnalogClock, 7, 32), it
checks that AnalogClock has the correct constructor signature.

Related discussion: https://github.com/Microsoft/TypeScript/issues/8917

Can an interface define the signature of a c#-constructor

Plug-in extendability is a favorite of mine...

What I do is make sure the plug-in either implements the interface or inherits the base class of the appropriate "plugin socket".

In some places base classes are more appropriate (if the plug-in is a kind of X),

in some interfaces are more appropriate (if the plug-in does IX).

I do not pass the context to the construct, instead I use a property for that and a parameterless public constructor.

This also enables easier deserialization of plug-ins using reflection.

How does interfaces with construct signatures work?


Construct signatures in interfaces are not implementable in classes; they're only for defining existing JS APIs that define a 'new'-able function. Here's an example involving interfaces new signatures that does work:

interface ComesFromString {
name: string;
}

interface StringConstructable {
new(n: string): ComesFromString;
}

class MadeFromString implements ComesFromString {
constructor (public name: string) {
console.log('ctor invoked');
}
}

function makeObj(n: StringConstructable) {
return new n('hello!');
}

console.log(makeObj(MadeFromString).name);

This creates an actual constraint for what you can invoke makeObj with:

class Other implements ComesFromString {
constructor (public name: string, count: number) {
}
}

makeObj(Other); // Error! Other's constructor doesn't match StringConstructable

C# constructor in interface

(I should have checked first, but I'm tired - this is mostly a duplicate.)

Either have a factory interface, or pass a Func<DataRow, T> into your constructor. (They're mostly equivalent, really. The interface is probably better for Dependency Injection whereas the delegate is less fussy.)

For example:

interface ISomething 
{
// Normal stuff - I assume you still need the interface
}

class Something : ISomething
{
internal Something(DataRow row)
{
// ...
}
}

class FooClass<T> where T : ISomething , new()
{
private readonly Func<DataRow, T> factory;

internal FooClass(Func<DataRow, T> factory)
{
this.factory = factory;
}

void BarMethod(DataRow row)
{
T t = factory(row);
}
}

...

FooClass<Something> x = new FooClass<Something>(row => new Something(row));

Can I enforce defining a specific constructor with an interface class?

There is no way to enforce the existence of a specific constructor for derived classes in the base class.

You can enforce the existence of a specific constructor by attempting to invoke that constructor, or using static_assert.

Something similar might be achievable not by a base class, but using a meta class... if they are accepted into the language in a future standard.

Why can't interface have constructor?

An interface doesn't have a constructor because an interface is not an instance of anything and there's nothing to construct. A certain type that implements an interface gets constructed when you create an instance of it so it can initialize its internal state.

An interface doesn't represent or encompass any kind of internal state (not even when some members of the interface expose data from the internal state of the type implementing it) so there's no need (or even meaning to) running a constructor for an interface.

Edit: your specific example ctor(int val); makes an assumption that all types implementing IX have some kind of int member variable but this is an implementation detail. The purpose of an interface is define what a type can do, not how it does it. The implementation of IX over different types may be very different, as long as they all provide a way internally to satisfy the interface.

For example, consider a type that needs a delimited string as input to work correctly:

class A : IX
{
public A ( string sData ) { ... }

// ...
}

The int required to satisfy IX could be part of the delimited string, yet, a single int constructor would be inappropriate for this class: a single int wouldn't be able to convey all other data needed for the correct operation of this class.



Related Topics



Leave a reply



Submit