TypeScript arayüzünde statik özelliği nasıl tanımlanır


Sadece TypeScript arayüzünde statik bir özellik ilan etmek istiyorum? Bu konuyla ilgili hiçbir şey bulamadım.

interface myInterface {
  static Name:string;
}

Bu mümkün mü?

Cevap #1

@Duncan ve @Bartvds'in cevabını takip edin, yıllar geçtikten sonra uygulanabilir bir yol sağlamak için buradayım.

Typescript 1.5 yayınlandıktan sonra bu noktada (@15 Haz '15), faydalı arayüzünüz

interface MyType {
    instanceMethod();
}

interface MyTypeStatic {
    new():MyType;
    staticMethod();
}

dekoratör yardımıyla bu şekilde uygulanabilir.

/* 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() {}
}

GitHub sorun 13462'deki yorumuma bakın.

görsel sonuç: Statik metod eksikliği konusunda bir ipucu ile derleme hatası.

Statik yöntem uygulandıktan sonra, yöntem eksik olduğuna dair ipucu.

Derleme, hem statik arayüz hem de normal arayüz yerine getirildikten sonra başarılı oldu.

Cevap #2

TypeScript'te bir arayüzde statik bir özellik tanımlayamazsınız.

Diyelim ki Date nesnesini değiştirmek istiyorsunuz, Date tanımlarına eklemeye çalışmak yerine, onu sarabilir veya basitçe Date'in yapmadığı şeyleri yapacak kendi zengin tarih sınıfınızı oluşturabilirsiniz.

class RichDate {
    public static MinValue = new Date();
}

Date, TypeScript'te bir arayüz (interface) olduğu için, extends anahtar kelimesini kullanarak bir sınıfla genişletemezsiniz; bu biraz üzücü çünkü eğer date bir sınıf olsaydı bu iyi bir çözüm olurdu.

Date nesnesini genişleterek prototipte bir MinValue özelliği sağlamak istiyorsanız, şunları yapabilirsiniz:

interface Date {
    MinValue: Date;
}

Date.prototype.MinValue = new Date(0);

Şu şekilde çağrıldı:

var x = new Date();
console.log(x.MinValue);

Ve eğer onu bir örnek olmadan kullanılabilir hale getirmek istersen, bunu da yapabilirsin... ama biraz titizdir.

interface DateStatic extends Date {
    MinValue: Date;
}

Date['MinValue'] = new Date(0);

Şu şekilde çağrıldı:

var x: DateStatic = <any>Date; // We aren't using an instance
console.log(x.MinValue);

Cevap #3

Statik değiştiriciler bir tür üyesinde görünemez (TS1070). Bu yüzden görevi çözmek için soyut bir sınıf ve kalıtım kullanmanızı öneririm:

Örnek

// 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());

Cevap #4

Arayüzü normal şekilde tanımlayabilirsiniz:

interface MyInterface {
    Name:string;
}

ama sadece yapamazsın

class MyClass implements MyInterface {
    static Name:string; // typescript won't care about this field
    Name:string;         // and demand this one instead
}

Bir sınıfın statik özellikleri için bu arayüzü takip etmesi gerektiğini ifade etmek için biraz hile yapmanız gerekir:

var MyClass: MyInterface;
MyClass = class {
    static Name:string; // if the class doesn't have that field it won't compile
}

Sınıfın adını bile koruyabilirsiniz, TypeScript (2.0) aldırmaz:

var MyClass: MyInterface;
MyClass = class MyClass {
    static Name:string; // if the class doesn't have that field it won't compile
}

Birçok arayüzden statik olarak miras almak istiyorsanız, önce bunları yeni bir arayüzde birleştirmeniz gerekecek:

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
}

Veya birleştirilmiş arayüze isim vermek istemiyorsanız şunu yapabilirsiniz:

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
}

Çalışan örnek

Cevap #5

Çözüm

I türünde bir örnek döner, I'nin geçerli bir somut yapıcı olduğundan ve C'nin I'yi genişlettiğinden emin olur:

type StaticImplements<I extends new (...args: any[]) => any, C extends I> = InstanceType<I>;

Veya daha genel bir sürüm, daha fazla durumda çalışmalıdır. any döndürür ve C'nin I'yi genişlettiğinden emin olur:

type StaticImplements<I, C extends I> = any;

Örnek yöntemli arayüz:

interface MyInstance {
    instanceMethod();
}

Statik metoda sahip arayüz:

interface MyClassStatic {
    new (...args: any[]): MyInstance;
    staticMethod();
}

Kendi metoduyla genişleten ve statik metod gerektiren sınıf:

class MyClass implements StaticImplements<MyClassStatic, typeof MyClass> {
    static staticMethod();
    static ownStaticMethod();
    instanceMethod();
    ownInstanceMethod();
}

Notlar

  • Tip kontrolü aslında C extends I içinde gerçekleşir
  • Parametre türü I için kısıtlama gerektiği şekilde değiştirilebilir
  • Dönüş türü, sınıfın implements aracılığıyla uygulayacağı şeydir; InstanceType<I> için sınıf aslında bir örnek türünü uygular, ancak object, {} veya any işe yaramalıdır

Akıl yürütme

Arayüzlerde statik yöntemlerin tanımlanması #33892 numaralı konuda tartışılmakta ve soyut statik yöntemler #34516 numaralı konuda tartışılmaktadır.

Val ve Aleksey'in cevaplarına dayanarak (teşekkürler), bu çözüm:

  • Ek çalışma zamanı değerleri gerektirmez
  • Sınıfın kendi üye bilgisi korunur
  • Yapıcı kısıtlamalarına izin verir

Test

Olduğu gibi - Oyun Alanı Bağlantısı:

MyClass.staticMethod(); // OK
MyClass.ownStaticMethod(); // OK
new MyClass().instanceMethod(); // OK
new MyClass().ownInstanceMethod(); // OK

MyClass içinden staticMethod kaldırmak istiyorsanız - Playground Link:

class MyClass implements StaticImplements<MyClassStatic, typeof MyClass> {} // Type 'typeof MyClass' does not satisfy the constraint 'MyClassStatic'. Property 'staticMethod' is missing in type 'typeof MyClass' but required in type 'MyClassStatic'.

MyClass içinden instanceMethod kaldırmak istiyorsanız - Playground Link:

class MyClass implements StaticImplements<MyClassStatic, typeof MyClass> {} // Class 'MyClass' incorrectly implements interface 'MyInstance'. Property 'instanceMethod' is missing in type 'MyClass' but required in type 'MyInstance'.

Cevap #6

Statik özellikler genellikle nesne için (küresel) yapıcı üzerinde yer alırken, "interface" anahtar kelimesi nesnenin örneklerine uygulanır.

Elbette, TypeScript'te sınıfı yazıyorsanız önceki verilen cevap doğrudur. Başkalarına yardımcı olması açısından, eğer başka bir yerde zaten uygulanmış bir nesneyi tanımlıyorsanız, statik özellikler de dahil olmak üzere global yapıcı şu şekilde ilan edilebilir:

declare var myInterface : {
  new(): Interface;
  Name:string;
}

İlgili makaleler