TypeScript - Arayüz özelliklerini adlandırmak için sınıf adını kullanın


Sanırım bu TS Playground, başarmaya çalıştığımı gösteriyor:

Özelliklerimi adlandırmak için bir değişken olarak Class.name kullanmak istiyorum.

class MyClass {
  readonly a: {b: number} = { b: 123 };

  constructor() {
    this.a.b = 1;
  }
}

// try1
interface Actions {
  [MyClass.name + '_action1']: string,
  [MyClass.name + '_action2']: number
}

interface Actions2 {
  MyClass_action1: string,
  MyClass_action2: number
}

// expect a and b to behave the same
const a: Actions2 = {
  MyClass_action1: '4',
  MyClass_action2: 1
}

const b: Actions = {
  MyClass_action1: '4',
  MyClass_action2: 1
}

Bu mümkün mü?

Cevap #1

Bu, geçici çözümler olmadan mümkün değil.

Sınıf yapıcılarının name özelliği, Function arayüzünden miras alındığı üzere string türündedir. Derleyici name özelliğinin string sabit türünü bilmez. Microsoft/TypeScript#43325 ve bu bağlantıya yönlendiren sorunlara bakın.

Çalışma zamanında bir class Foo {⋯} sınıfının Foo.name === "Foo" olacağını kesin olarak bildiğimizi varsayarsak (yani bir static özelliği tarafından geçersiz kılındığı veya sınıfın küçültüldüğü veya bozulduğu garip uç durumlar hakkında endişelenmediğimiz anlamına gelir), TypeScript yine de Foo.name türünün "Foo" olmasına kolayca izin veremez. Bunun nedeni, bir sınıfın statik tarafının bir tür hiyerarşisi oluşturmasıdır; yani class Bar extends Foo {⋯} gibi bir sınıfınız varsa, TypeScript Bar. name Foo.name ile atanabilir olmalıdır. Yani eğer Foo.name türü "Foo" ise, Bar.name de tür olarak "Foo" olmalıdır. Ancak, bu çalışma zamanında doğru olma olasılığı oldukça düşüktür. Temelde TypeScript, statik kalıtımla ilgili karmaşıklıklardan çoğunlukla kaçınmaya çalışır, bu da insanların istediği kadar güçlü olmayan türlere yol açar.

Bir gün JavaScript'in C#'ta olan nameof operatörünü tanıtması belirsiz bir şekilde mümkün, ve sonra TypeScript bunu destekleyecek (bkz. microsoft/TypeScript#1579), ve sonra TypeScript tür sistemi içinde bir sınıfın adını resmi olarak desteklenen bir şekilde çıkarabiliriz.

Ama bunlardan herhangi biri gerçekleşene kadar, bunu kendiniz belirtmek zorundasınız. Bunu, bilgileri manuel olarak birleştirerek yapabilirsiniz, işte böyle:

declare namespace MyClass {
  export const name: "MyClass"
}

Ve ardından anahtarlarınızı şablon literal türleri aracılığıyla tanımlayabilirsiniz (bu, tür düzeyinde string birleştirmeyi elde etmenin tek yoludur):

const action1 = `${MyClass.name}_action1` as const;
const action2 = `${MyClass.name}_action2` as const;
interface Actions {
  [action1]: string,
  [action2]: number
}

Bu ihtiyaçlarınızı karşılayabilir veya karşılamayabilir, ama şimdilik ya bunun gibi bir şey yaparsınız ya da vazgeçersiniz.

Koda yönelik oyun alanı bağlantısı