1

I am new to Typescript and ran into the following question when trying to implement a interface in a class:

interface TestInterface {
  x: number
}

class Test implements TestInterface {
  constructor() {
    this.x = 0
  }
}

// Class 'Test' incorrectly implements interface 'TestInterface'.
// Property 'x' is missing in type 'Test' but required in type 'TestInterface'.

But if I add x: number to Test before constructor, it works. So I am guessing if you wanted to check the type of a property initialized in the constructor, you have to specify that on the class itself. Then what is implement and the interface for? And if I want to use the interface to check the type of its instances, wouldn't it be repetitive since I have to write it in two places?

3
  • interface defines a contract or a structure - set of properties and methods, that are guaranteed to be present on a class which implements that interface. But class has to implement those on its own - interface is just a contract and not an implementation. Commented Aug 17, 2021 at 0:44
  • I guess they could have made it so that interface members are implicit members when assigned to save the declaration in the class, but that's not how most langs with interfaces work. The interface always just defines the contract to be fulfilled and the class must provide the matching implementation. There might be optimization reasons for that, IDK. Commented Aug 17, 2021 at 0:46
  • The way you're trying to use implements is what the extends keyword is for (note: extends requires you to convert the interface to a class) Commented Aug 17, 2021 at 0:56

3 Answers 3

3

Code in a constructor is not something that Typescript can check to determine if your class correctly implements the interface. It would be impossible for Typescript to check all the assignments in your code to ensure the types are correct, so you need to declare the types statically. The point of interface and implements is not to reduce the amount of code you have to write, it's to declare the type of objects in your code, so that Typescript can statically check that your code is self-consistent with regard to types.

By saying the class implements the interface, you are effectively asking Typescript to keep you honest and check that the types are indeed consistent. If Typescript merely trusted that you'd do the right thing in your constructor, it would not be very effective! Note that constructors may contain conditional logic, loops and other code that mean it is not possible even in principle for Typescript to analyse the constructor code to determine if you are keeping the contract you commit to with implements.

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

2 Comments

I see, could I understand an interface as something that you would normally implement for multiple different classes? Whereas the type-checking for each constructor is more so a self-regulating step when creating a class, implementing an interface helps check if those restrictions are consistent across classes?
It's not necessarily just for multiple classes (or objects). Because JS alone does not declare types as such, interface is simply the TS way of specifying the shape of your data. If you define the types of the fields on your class, then you don't necessarily also need to specify that it implements such-and-such an interface. A large part of TS's value is in checking the way you consume the object elsewhere in your code, whether or not multiple objects implement the same interface. I would say that's most often not the case.
1

So I am guessing if you wanted to check the type of a property initialized in the constructor, you have to specify that on the class itself.

You are exactly right!

Then what is implement and the interface for?

An interface is intended to be a "contract". Here's a simple example:

interface Connectable {
  connect: () => Promise<void>
}

const robustConnect = async (connection: Connectable) => {
  try {
    await connection.connect();
  } catch (error) {
    console.warn(`there was an error, let's try once more`);
    await connection.connect();
  }
}

In this example, we've typed the function robustConnect so that it can receive just any object that has a connect method. This is the most useful usage of an interface: giving a name to a type so that it is more legible.

In other OO languages, an interface would be the only way to declare a type like that, and you would have to extend the interface to use robustConnect. Otherwise, the compilation step would fail. Since javascript isn't inherently an object-oriented language and is dynamically typed, that restriction isn't there. So the implements keyword can feel useless. At best, you could use it to help yourself when writing classes: just use the implements keyword and let the TypeScript compiler tell you what you are missing. But that's about it.

Hope this helps.

Comments

-2

Low key You need to learn Object Oriented Programming. Your question is a core principle of oop.

When you find a new job, you sign a contract, the contract specifies your role, duties, behavior and more; so you need to follow the contract so if you implement an interface your class need to follow the structure of your interface.

If for instance you find that redundant instead of creating a class use pure objects

const obj:Obj ={
name: “eneto”
};

Plus also your statement “But if I add x: number to Test before constructor, it works. So I am guessing if you wanted to check the type of a property initialized in the constructor, you have to specify that on the class itself. Then what is implement and the interface for?” doesn’t have sense, because typescript checks your code at compilation fase, but once your code compiles it becomes JavaScript which doesn’t have static types

Comments

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.