Eu só quero declarar uma propriedade estática na interface typescript ? Eu não encontrei nada sobre isso.
interface myInterface {
static Name:string;
}
É possível?
Eu só quero declarar uma propriedade estática na interface typescript ? Eu não encontrei nada sobre isso.
interface myInterface {
static Name:string;
}
É possível?
Respostas:
Você não pode definir uma propriedade estática em uma interface em TypeScript.
Digamos que você queira alterar o Date
objeto, em vez de tentar adicionar às definições de Date
, você pode embrulhá-lo ou simplesmente criar sua classe de data rica para fazer o que Date
não faz.
class RichDate {
public static MinValue = new Date();
}
Como Date é uma interface em TypeScript, você não pode estendê-la com uma classe usando a extends
palavra - chave, o que é uma pena, pois seria uma boa solução se date fosse uma classe.
Se você deseja estender o objeto Date para fornecer uma MinValue
propriedade no protótipo, você pode:
interface Date {
MinValue: Date;
}
Date.prototype.MinValue = new Date(0);
Chamado usando:
var x = new Date();
console.log(x.MinValue);
E se você quiser torná-lo disponível sem uma instância, você também pode ... mas é um pouco complicado.
interface DateStatic extends Date {
MinValue: Date;
}
Date['MinValue'] = new Date(0);
Chamado usando:
var x: DateStatic = <any>Date; // We aren't using an instance
console.log(x.MinValue);
extends
palavra - chave. Você simplesmente não pode estender uma interface com uma classe (o que você precisaria fazer para adicionar uma propriedade estática).
Siga a resposta de @Duncan's @ Bartvds, aqui para fornecer uma maneira viável depois que anos se passaram.
Neste ponto, após o lançamento do Typescript 1.5 (@Jun 15 '15), sua interface útil
interface MyType {
instanceMethod();
}
interface MyTypeStatic {
new():MyType;
staticMethod();
}
pode ser implementado desta forma com a ajuda do decorador.
/* class decorator */
function staticImplements<T>() {
return <U extends T>(constructor: U) => {constructor};
}
@staticImplements<MyTypeStatic>() /* this statement implements both normal interface & static interface */
class MyTypeClass { /* implements MyType { */ /* so this become optional not required */
public static staticMethod() {}
instanceMethod() {}
}
Consulte meu comentário no github open issue 13462 .
resultado visual: erro de compilação com uma dica de método estático ausente.
Após a implementação do método estático, falta a dica para o método.
A compilação passou depois que a interface estática e a interface normal foram cumpridas.
Você pode definir a interface normalmente:
interface MyInterface {
Name:string;
}
mas você não pode simplesmente fazer
class MyClass implements MyInterface {
static Name:string; // typescript won't care about this field
Name:string; // and demand this one instead
}
Para expressar que uma classe deve seguir esta interface para suas propriedades estáticas, você precisa de alguns truques:
var MyClass: MyInterface;
MyClass = class {
static Name:string; // if the class doesn't have that field it won't compile
}
Você pode até manter o nome da classe, o TypeScript (2.0) não se importará:
var MyClass: MyInterface;
MyClass = class MyClass {
static Name:string; // if the class doesn't have that field it won't compile
}
Se você deseja herdar de muitas interfaces estaticamente, você terá que fundi-las primeiro em uma nova:
interface NameInterface {
Name:string;
}
interface AddressInterface {
Address:string;
}
interface NameAndAddressInterface extends NameInterface, AddressInterface { }
var MyClass: NameAndAddressInterface;
MyClass = class MyClass {
static Name:string; // if the class doesn't have that static field code won't compile
static Address:string; // if the class doesn't have that static field code won't compile
}
Ou, se não quiser nomear a interface mesclada, você pode fazer:
interface NameInterface {
Name:string;
}
interface AddressInterface {
Address:string;
}
var MyClass: NameInterface & AddressInterface;
MyClass = class MyClass {
static Name:string; // if the class doesn't have that static field code won't compile
static Address:string; // if the class doesn't have that static field code won't compile
}
Exemplo de trabalho
@staticImplements
.
reply(msg: IBotMsg): Promise<IBotReply>
As propriedades estáticas geralmente são colocadas no construtor (global) do objeto, enquanto a palavra-chave "interface" se aplica a instâncias do objeto.
A resposta anterior fornecida é obviamente correta se você estiver escrevendo a classe em TypeScript. Pode ser útil saber que se você está descrevendo um objeto que já está implementado em outro lugar, o construtor global incluindo propriedades estáticas pode ser declarado assim:
declare var myInterface : {
new(): Interface;
Name:string;
}
Os modificadores estáticos não podem aparecer em um membro de tipo (erro do TypeScript TS1070). É por isso que recomendo usar uma classe abstrata para resolver a missão:
Exemplo
// Interface definition
abstract class MyInterface {
static MyName: string;
abstract getText(): string;
}
// Interface implementation
class MyClass extends MyInterface {
static MyName = 'TestName';
getText(): string {
return `This is my name static name "${MyClass.MyName}".`;
}
}
// Test run
const test: MyInterface = new MyClass();
console.log(test.getText());
A solução de @duncan acima especificando new()
para o tipo estático também funciona com interfaces:
interface MyType {
instanceMethod();
}
interface MyTypeStatic {
new():MyType;
staticMethod();
}
implement
?
MyType
(como em class Foo implements MyType
). A interface estática só é realmente útil em definições, ao descrever o código JS existente.
Se você estiver procurando definir uma classe estática (ou seja, todos os métodos / propriedades são estáticos), você pode fazer algo assim:
interface MyStaticClassInterface {
foo():string;
}
var myStaticClass:MyStaticClassInterface = {
foo() {
return 'bar';
}
};
Neste caso, a "classe" estática é realmente apenas um objeto-js simples, que implementa todos os métodos de MyStaticClassInterface
Sim, é possível. Aqui está a solução
export interface Foo {
test(): void;
}
export namespace Foo {
export function statMethod(): void {
console.log(2);
}
}
Foo
para substituir uma definição de classe? onde a classe Foo implementaria o statMethod () isso parece um pouco um hack, especialmente porque os namespaces estão meio que obsoletos agora ...
waiting more feedback
. Portanto, você pode esperar até que métodos estáticos sejam adicionados à interface ou fazer desta forma.
export namespace
é realmente a implementação de sua classe? Isso parece estar distorcendo muito as coisas. Eu me pergunto o que mais isso quebra nas aulas?
Outra opção não mencionada aqui é definir a variável com um tipo que representa a interface estática e atribuir a ela uma expressão de classe:
interface MyType {
instanceMethod(): void;
}
interface MyTypeStatic {
new(): MyType;
staticMethod(): void;
}
// ok
const MyTypeClass: MyTypeStatic = class MyTypeClass {
public static staticMethod() { }
instanceMethod() { }
}
// error: 'instanceMethod' is missing
const MyTypeClass1: MyTypeStatic = class MyTypeClass {
public static staticMethod() { }
}
// error: 'staticMethod' is missing
const MyTypeClass2: MyTypeStatic = class MyTypeClass {
instanceMethod() { }
}
O efeito é o mesmo que na resposta com decoradores , mas sem sobrecarga de decoradores
Sugestão / discussão relevante no GitHub
Você pode mesclar interface com namespace usando o mesmo nome:
interface myInterface { }
namespace myInterface {
Name:string;
}
Mas essa interface só é útil para saber se ela possui propriedades Name
. Você não pode implementá-lo.
Eu encontrei uma maneira de fazer isso (sem decoradores) para meu caso de uso específico.
A parte importante que verifica se há membros estáticos é IObjectClass
e usando cls: IObjectClass<T>
no createObject
método:
//------------------------
// Library
//------------------------
interface IObject {
id: number;
}
interface IObjectClass<T> {
new(): T;
table_name: string;
}
function createObject<T extends IObject>(cls: IObjectClass<T>, data:Partial<T>):T {
let obj:T = (<any>Object).assign({},
data,
{
id: 1,
table_name: cls.table_name,
}
)
return obj;
}
//------------------------
// Implementation
//------------------------
export class User implements IObject {
static table_name: string = 'user';
id: number;
name: string;
}
//------------------------
// Application
//------------------------
let user = createObject(User, {name: 'Jimmy'});
console.log(user.name);
Embora a palavra-chave estática não seja suportada na interface em Typescript, podemos alcançá-la criando um function interface
que tenha um membro estático.
Em meu código a seguir, criei uma interface de função Factory
que tem dois membros estáticos serialNumber
e printSerial .
// factory is a function interface
interface Factory<T> {
(name: string, age: number): T;
//staic property
serialNumber: number;
//static method
printSrial: () => void;
}
class Dog {
constructor(public name: string, public age: number) { }
}
const dogFactory: Factory<Dog> = (name, age) => {
return new Dog(name, age);
}
// initialising static members
dogFactory.serialNumber = 1234;
dogFactory.printSrial = () => console.log(dogFactory.serialNumber);
//instance of Dog that DogFactory creates
const myDog = dogFactory("spike", 3);
//static property that returns 1234
console.log(dogFactory.serialNumber)
//static method that prints the serial 1234
dogFactory.printSrial();
Eu implementei uma solução como a de Kamil Szot e teve um efeito indesejado. Eu não tenho reputação suficiente para postar isso como um comentário, então eu posto aqui caso alguém esteja tentando essa solução e leia isso.
A solução é:
interface MyInterface {
Name: string;
}
const MyClass = class {
static Name: string;
};
No entanto, usar uma expressão de classe não me permite usar MyClass
como um tipo. Se eu escrever algo como:
const myInstance: MyClass;
myInstance
acabou sendo do tipo any
, e meu editor mostra o seguinte erro:
'MyClass' refers to a value, but is being used as a type here. Did you mean 'typeof MyClass'?ts(2749)
Acabo perdendo uma digitação mais importante do que a que eu queria conseguir com a interface para a parte estática da aula.
A solução de Val usando um decorador evita essa armadilha.