Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to define class which implements interface without implementation?

Is it possible to define a class which has interface variables without implementation in TypeScript?

For example:

interface ITask {
  id: number;
  title: string;
}

class Task implements ITask {
  // without implementation
}

The above code will cause an error like this:

Type 'Task' is missing the following properties from type 'Task', ...

I also tried the following code, but it also caused an error:

class Task extends ITask {
  // without implementation
}
TypeError: Class extends value undefined is not a constructor or null

I am asking this question because I want to generate classes from interfaces automatically, without changing any variable. I don't want to copy and paste all the variables.

like image 257
subdiox Avatar asked Nov 16 '25 04:11

subdiox


2 Answers

There's a lot of type safety that the --strict suite of compiler options gives you. (If you're not using it, then you should.) It sounds like you're trying to circumvent some of it and It's not clear to me why you want to do this. If you convince the compiler that the class has implemented the interface without actually doing so, all you're doing is suppressing compiler warnings that are meant prevent having runtime errors. As it stands, the following code produces compiler warnings:

const t: ITask = new Task(); // error here
t.id.toFixed(2); 

which is a good thing, because at runtime, t.id will be undefined, so t.id.toFixed() will throw an exception. If you force Task implements ITask to work, then you'd get no compiler warnings, but you'd still get a runtime error.


If you really want to do this, you can use declaration merging to reopen the Task's instance interface and have it extend ITask:

interface Task extends ITask { } // merging
class Task implements ITask {
}

Now there's no error, but of course you run into the same problem here:

const t = new Task();
t.id.toFixed() // compiles without error

If you want to be safe, you could make Task implement Partial<ITask> using the Partial<T> utility type to make the properties from ITask optional:

interface Task extends Partial<ITask> { }
class Task implements Partial<ITask> {
}

And now the compiler will expect a Task to possibly have those fields, but you need to check them for nullishness before using them, such as by using the optional chaining operator (?.):

const t = new Task();
t.id.toFixed() // compiler error now
t.id?.toFixed(); // okay

Playground link to code

like image 105
jcalz Avatar answered Nov 18 '25 19:11

jcalz


You can use this approach

interface IUser {
  name: string;
  email: string;
  phone: string;
}

interface User extends IUser {}
class User {
  constructor(user: IUser) {
    Object.assign(this, user);
  }

  getFullName() {
    return this.name;
  }
}

const userData: IUser = {
  email: "[email protected]",
  phone: "1234567890",
  name: "John Doe",
};

const user = new User(userData);
console.log(user.email); // [email protected]
console.log(user.getFullName()); // John Doe
like image 35
adityaa72 Avatar answered Nov 18 '25 21:11

adityaa72