TypeScript arabiriminde statik özellik nasıl tanımlanır


123

Sadece typcript arayüzünde statik bir özellik mi ilan etmek istiyorum ? Bununla ilgili hiçbir şey bulamadım.

interface myInterface {
  static Name:string;
}

Mümkün mü?


Tam olarak neyi modellemeye çalışıyorsun?
Ryan Cavanaugh

5
Bar'ın da bir sınıf olduğu 'class Foo implements Bar' kullanmayı düşünün. TS'deki diğer sınıflara göre sınıfları 'uygulayabilirsiniz'.
Tobias Cudnik

Yanıtlar:


46

TypeScript'te bir arabirimde statik özellik tanımlayamazsınız.

DateNesneyi, tanımlarına eklemeye çalışmak yerine değiştirmek istediğinizi varsayalım, Dateonu sarmalayabilir veya yapmayan şeyleri yapmak için zengin tarih sınıfınızı oluşturabilirsiniz Date.

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

Tarih, TypeScript'te bir arabirim olduğundan, onu extendsanahtar sözcüğü kullanarak bir sınıfla genişletemezsiniz , bu biraz utanç verici, çünkü tarih bir sınıfsa bu iyi bir çözüm olurdu.

MinValuePrototip üzerinde bir özellik sağlamak için Date nesnesini genişletmek isterseniz şunları yapabilirsiniz:

interface Date {
    MinValue: Date;
}

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

Kullanılarak arandı:

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

Ve bir örnek olmadan kullanılabilir hale getirmek istiyorsanız, bunu da yapabilirsiniz ... ama bu biraz telaşlı.

interface DateStatic extends Date {
    MinValue: Date;
}

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

Kullanılarak arandı:

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

1
@Rajagopal Açık olmak gerekirse, extendsanahtar kelimeyi kullanarak TS'deki arayüzleri genişletebilirsiniz . Bir arabirimi bir sınıfla genişletemezsiniz (statik bir özellik eklemek için yapmanız gereken).
Jude Fisher

Steve - 'Tarih, TypeScript'te bir arayüz olduğu için, onu extends anahtar sözcüğünü kullanarak genişletemezsiniz' - bu doğru değil, değil mi?
Jude Fisher

1
Arayüzü genişletebilirsiniz, ancak onu bir sınıfla genişletemezsiniz, yalnızca uygulayabilirsiniz. Bunu netleştirmedim.
Fenton

@Nikos fikrini ikinci olurdum. Arayüzlerin kalıtımı, okunabilirliği artırma amacını ortadan kaldırmaz ve dolayısıyla sürdürülebilirliği azaltır mı? Yeni bir arayüz yerine neden arayüzlerin kalıtımının kullanıldığına dair mantıklı bir fikir verebilecek biri var mı?
Tomas Hesse

@TomasHesse bu (ilk) soruya tek bir doğru cevap yok. Bu kararlar, rakip talepler arasındaki ödünleşmedir ve doğru cevap, uygun bağlamda ödünleşmeyi değerlendirmektir.
Fenton

100

Yıllar sonra uygulanabilir bir yol sağlamak için @ Duncan'ın @ Bartvds'ın cevabını buradan takip edin.

Typecript 1.5 yayınlandıktan sonra (15 Haziran 2015), yardımcı arayüzünüz

interface MyType {
    instanceMethod();
}

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

dekoratör yardımı ile 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() {}
}

13462 numaralı github açık sayısındaki yorumuma bakın .

görsel sonuç: Eksik bir statik yöntem ipucu ile derleme hatası. görüntü açıklamasını buraya girin

Statik yöntem uygulandıktan sonra, yöntem eksik için ipucu. görüntü açıklamasını buraya girin

Hem statik arayüz hem de normal arayüz yerine getirildikten sonra derleme geçti. görüntü açıklamasını buraya girin


5
Cevabınız cevaptır. Çok teşekkür ederim.
Typecript

Bu cevap
Typescript

2
@mmmeff 3.0.1 ile test ettim ve çalışıyor. "Çalışmıyorum" derken ne demek istiyorsun? Herhangi bir hata mesajı var mı?
Val

1
@Chklang Teşekkürler! Cevabımı önerinizle güncelledim
Val

1
Bunu Soyut bir sınıfla nasıl yapabiliriz?
geoyws

16

Arayüzü normal olarak 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 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 tutabilirsiniz, TypeScript (2.0) bunu önemsemez:

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

Statik olarak birçok arabirimden miras almak istiyorsanız, önce bunları yenisiyle birleştirmeniz gerekir:

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üzü adlandırmak istemiyorsanız şunları 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ışma örneği


TS2322 hatası alıyorum: Anonim sınıf türe atanamaz
JoshuaDavid

@FireCoding Hangi TypeScript sürümünü kullanıyorsunuz? Örneklerim 2.0
Kamil Szot

Bu, özel dekoratörden daha basit bir çözümdür @staticImplements.
Robert Penner

1
Bunun harika bir çözüm olduğunu düşünüyorum. zaman uyumsuz statik yöntemler için de kullanabilirsinizreply(msg: IBotMsg): Promise<IBotReply>
dcsan

Hem statik hem de örnek yöntemlerini tanımlamanın bir yolu var mı yoksa tüm yöntemler artık yalnızca statik mi?
dcsan

15

Statik özellikler genellikle nesnenin (genel) yapıcısına yerleştirilirken, "arabirim" anahtar sözcüğü nesnenin örnekleri için geçerlidir.

Sınıfı TypeScript'te yazıyorsanız, önceki cevap elbette doğrudur. Başkalarının, zaten başka bir yerde uygulanmış bir nesneyi tanımlıyorsanız, statik özellikleri içeren genel yapıcının şu şekilde bildirilebileceğini bilmelerine yardımcı olabilir:

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

düzenleme: aşağıda
Bartvds

Typescript 1.5 yayımlandıktan (6.15.2015) sonra bu noktada, burada bir sınıfın statik üyelerini tanımlamak için uygulanabilir bir yoldur. stackoverflow.com/a/43674389/681830
Val

8

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

Misal

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

Evet, cevap bu!
vintproykt

7

@ duncan'ın yukarıdaki new()statik türü belirleme çözümü , arayüzlerle de çalışır:

interface MyType {
    instanceMethod();
}

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

Bunlardan hangisi benim sınıfım olurdu implement?
Denis Pshenov

2
Bu noktada, statik üyeleri tanımlamak için bir arabirim kullanamazsınız, yalnızca örnek üyelerini. Yani bu örnekte sınıfınız MyType(olduğu gibi class Foo implements MyType) uygulayacaktır . Statik arayüz yalnızca mevcut JS kodunu açıklarken tanımlarda gerçekten kullanışlıdır.
Bartvds

Typescript 1.5 yayımlandıktan (6.15.2015) sonra bu noktada, burada bir sınıfın statik üyelerini tanımlamak için uygulanabilir bir yoldur. stackoverflow.com/a/43674389/681830
Val

4

Statik bir sınıf tanımlamak istiyorsanız (yani, tüm yöntemler / özellikler statiktir), şöyle bir şey yapabilirsiniz:

interface MyStaticClassInterface {
  foo():string;
}

var myStaticClass:MyStaticClassInterface = {
  foo() {
    return 'bar';
  }
};

Bu durumda, statik "sınıf" gerçekten yalnızca düz-ol'-js-nesnesidir ve tüm yöntemleri MyStaticClassInterface


4

Evet mümkün. İşte çözüm

export interface Foo {

    test(): void;
}

export namespace Foo {

    export function statMethod(): void {
        console.log(2);
    }

}

Bu harika! Tam olarak ihtiyacım olan şey
Umar Farooq Khawaja

1
@UmarFarooqKhawaja Yardımcı olduğum için mutluyum!
Pavel_K

yani bu, Foobir sınıf tanımını yerine getirmek için bir ad alanı kullanıyor ? Foo Sınıfı statMethod () 'u uygulayacağı yerde bu biraz hack gibi görünüyor, özellikle ad alanları artık kullanımdan kaldırıldı ...
dcsan

@dcsan Evet, biraz hackleniyor. Ama ne yapmalı? Daktilo ile ilgili pek çok konu uzun yıllar boyunca etiketli olarak açıktır waiting more feedback. Yani ya arayüze statik yöntemler eklenene kadar beklersiniz ya da bu şekilde yaparsınız.
Pavel_K

ama aynı zamanda tam olarak anlayamıyorum .. export namespaceaslında sizin Sınıf uygulamanız mı? Bu işleri çok fazla büküyor gibi görünüyor. Acaba sınıflarda başka neler bozulur?
dcsan

3

Burada bahsedilmeyen başka bir seçenek, değişkeni statik arabirimi temsil eden bir türle tanımlamak ve ona sınıf ifadesi atamaktır:

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

Etki dekoratörlerle aynıdır , ancak dekoratörlerin yükü yoktur.

Oyun alanı

GitHub'da ilgili öneri / tartışma


2

Sen edebilirsiniz ad ile arayüz birleştirme aynı adı kullanarak:

interface myInterface { }

namespace myInterface {
  Name:string;
}

Ancak bu arayüz yalnızca özelliğine sahip olduğunu bilmek yararlıdır Name. Uygulayamazsınız.


2

Bunu özel kullanım durumum için (dekoratörler olmadan) yapmanın bir yolunu buldum.

Statik üyeler için denetler olduğunu önemli bir parçası IObjectClassve kullanma cls: IObjectClass<T>içinde createObjectyöntemle:

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

0

Typescript arayüzünde statik anahtar kelime desteklenmese function interfacede statik üyesi olan bir oluşturarak bunu başarabiliriz .

Aşağıdaki kodumdaFactory iki statik üye serialNumberve printSerial içeren bir işlev arabirimi oluşturdum .

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

0

Kamil Szot'unki gibi bir çözüm uyguladım ve istenmeyen bir etkisi var. Bunu bir yorum olarak yayınlayacak kadar itibarım yok, bu yüzden birisinin bu çözümü denemesi ve bunu okuması durumunda buraya gönderiyorum.

Çözüm şudur:

interface MyInterface {
    Name: string;
}

const MyClass = class {
    static Name: string;
};

Ancak, bir sınıf ifadesi kullanmak tür MyClassolarak kullanmama izin vermiyor . Şöyle bir şey yazarsam:

const myInstance: MyClass;

myInstancetürden olduğu ortaya çıktı anyve editörüm şu hatayı gösteriyor:

'MyClass' refers to a value, but is being used as a type here. Did you mean 'typeof MyClass'?ts(2749)

Sınıfın statik kısmı için arayüzle elde etmek istediğimden daha önemli bir yazımı kaybediyorum.

Val'in bir dekoratör kullanan çözümü bu tuzağı önler.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.