Pesquisa de site

typescript - É possível definir uma classe que implemente uma interface sem implementação?


É possível definir uma classe que tenha variáveis de interface sem implementação em TypeScript?

Por exemplo:

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

class Task implements ITask {
  // without implementation
}

O código acima causará um erro como este:

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

Eu também tentei o seguinte código, mas ele também causou um erro:

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

Estou fazendo esta pergunta porque quero gerar classes a partir de interfaces automaticamente, sem alterar nenhuma variável. Eu não quero copiar e colar todas as variáveis.

Resposta #1

Há muita segurança de tipo que o conjunto de opções de compilador --strict oferece. (Se você não está usando, deveria usar.) Parece que você está tentando contornar parte disso e não está claro para mim por que você quer fazer isso. Se você convencer o compilador de que a classe implementou a interface sem realmente fazê-lo, tudo o que você estará fazendo é suprimir avisos do compilador que têm o objetivo de prevenir erros em tempo de execução. Como está, o código a seguir gera avisos do compilador:

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

o que é algo bom, porque em tempo de execução, t.id será undefined, então t.id.toFixed() lançará uma exceção. Se você forçar Task implements ITask a funcionar, então não receberia avisos do compilador, mas ainda assim receberia um erro em tempo de execução.


Se você realmente quiser fazer isso, pode usar a mesclagem de declarações para reabrir a interface de instância de Task e fazê-la estender ITask:

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

Agora não há erro, mas é claro que você encontra o mesmo problema aqui:

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

Se você quiser estar seguro, você poderia fazer Task implementar Partial<ITask> usando o tipo de utilitário Partial<T> para tornar as propriedades de ITask opcionais:

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

E agora o compilador esperará que uma Task possivelmente tenha esses campos, mas você precisa verificá-los quanto a nulidade antes de usá-los, como usando o operador de encadeamento opcional (?.):

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

Link do playground para o código

Resposta #2

Você pode usar essa abordagem

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 ",
  phone: "1234567890",
  name: "John Doe",
};

const user = new User(userData);
console.log(user.email); // [email 
console.log(user.getFullName()); // John Doe

Artigos relacionados