Bagaimana mengimplementasikan konstanta kelas dalam naskah?

430

Dalam TypeScript, constkata kunci tidak dapat digunakan untuk mendeklarasikan properti kelas. Melakukannya menyebabkan kesalahan kompiler dengan "Anggota kelas tidak dapat memiliki kata kunci 'const'."

Saya menemukan diri saya perlu menunjukkan dengan jelas dalam kode bahwa properti tidak boleh diubah. Saya ingin IDE atau kompiler untuk kesalahan jika saya mencoba untuk memberikan nilai baru ke properti setelah dideklarasikan. Bagaimana kalian mencapai ini?

Saat ini saya menggunakan properti read-only, tetapi saya baru mengenal Typescript (dan JavaScript) dan bertanya-tanya apakah ada cara yang lebih baik:

get MY_CONSTANT():number {return 10};

Saya menggunakan naskah 1.8. Saran?

PS: Saya sekarang menggunakan naskah 2.0.3, jadi saya sudah menerima jawaban David

Jus kumbang
sumber

Jawaban:

652

TypeScript 2.0 memiliki readonlypengubah :

class MyClass {
    readonly myReadOnlyProperty = 1;

    myMethod() {
        console.log(this.myReadOnlyProperty);
        this.myReadOnlyProperty = 5; // error, readonly
    }
}

new MyClass().myReadOnlyProperty = 5; // error, readonly

Ini bukan konstanta karena memungkinkan penugasan dalam konstruktor, tetapi kemungkinan besar itu bukan masalah besar.

Solusi alternatif

Alternatifnya adalah menggunakan statickata kunci dengan readonly:

class MyClass {
    static readonly myReadOnlyProperty = 1;

    constructor() {
        MyClass.myReadOnlyProperty = 5; // error, readonly
    }

    myMethod() {
        console.log(MyClass.myReadOnlyProperty);
        MyClass.myReadOnlyProperty = 5; // error, readonly
    }
}

MyClass.myReadOnlyProperty = 5; // error, readonly

Ini bermanfaat karena tidak dapat ditugaskan di konstruktor dan hanya ada di satu tempat.

David Sherret
sumber
31
Untuk mengakses properti dari luar kelas, Anda harus menambahkan exportkata kunci sebelum classmaupun public staticsebelum readonlykata kunci. Lihat di sini: stackoverflow.com/a/22993349
cbros2008
Pertanyaan. Tidak mengerti mengapa Anda membutuhkan nama kelas untuk menggunakan properti readOnly di dalam kelas itu sendiri? '
MyClass.myReadonlyProperty
@SaiyaffFarouk Jika saya memahami pertanyaan Anda, jawabannya adalah bahwa properti statis ada sebagai bagian dari kelas, bukan pada instance kelas. Jadi, Anda mengaksesnya menggunakan nama kelas, bukan variabel yang berisi turunan kelas.
JeffryHouser
1
The export(modul eksternal) dan publickata kunci yang terkait dengan pertanyaan ini / jawaban, tetapi pada topik ketegasan, saya pribadi merasa sangat mudah untuk mengatakan bahwa seorang anggota publik ketika kata kunci tidak ada. Saya tidak peduli dengan itu untuk alasan itu dan karena itu menambahkan lebih banyak suara & mengetik tidak perlu. Ini juga membuat anggota publik lebih berbeda dari yang ditandai sebagai privateatau protected. Bagaimanapun, hanya pendapat saya :)
David Sherret
Bagaimana dengan kelas anonim? Adakah ide tentang cara mengakses static readonly myReadOnlyPropertyketika kelas dideklarasikan export default class { ... }? Mencoba this.myVar, self.myVar, statis, default ... tidak berfungsi ... (EDIT: default.myVar tampaknya menjadi solusinya, tapi saya mendapatkan kesalahan ketik)
Alcalyn
67

Konstanta dapat dideklarasikan di luar kelas dan digunakan di dalam kelas Anda. Kalau tidak, getproperti adalah solusi yang bagus

const MY_CONSTANT: string = "wazzup";

export class MyClass {

    public myFunction() {

        alert(MY_CONSTANT);
    }
}
j3ff
sumber
6
Terima kasih; Saya khawatir tentang implementasi ini karena ini tidak portabel (dalam model, konstanta sebenarnya bukan bagian dari kelas) dan ia membocorkan informasi ke dalam cakupan yang lebih besar, tetapi ia memiliki keuntungan sebagai konstanta nyata jadi saya menang ' t dapat mengubahnya tanpa menaikkan lonceng alarm.
BeetleJuice
1
Saya memahami keprihatinan ini dan saya menemukan penggunaan getproperti sangat tepat dalam kasus Anda
j3ff
3
Per angular.io/docs/ts/latest/guide/style-guide.html silakan gunakan unta kaase alih-alih huruf besar. Huruf besar untuk konstanta tidak disarankan.
Vadim Kirilchuk
12
Styleguide sudut, bukan TypeScript styleguide .. Pertanyaan mengenai TypeScript khusus
VeldMuijz
4
@ Esko Saya percaya bahwa dalam naskah skrip const terbatas pada file karena setiap file adalah modul. Untuk membuatnya dapat diakses di luar, Anda harus mendeklarasikannya dengan export constdan kemudian mengimpornya dari file lain. Akan sangat mudah untuk diuji. Cukup nyatakan a constdalam satu file, dan coba gunakan di file lain tanpa ekspor / impor, atau gunakan dari konsol browser.
BeetleJuice
42

Anda bisa menandai properti dengan readonlypengubah dalam deklarasi Anda:

export class MyClass {
  public static readonly MY_PUBLIC_CONSTANT = 10;
  private static readonly myPrivateConstant = 5;
}

@lihat buku menyelam Deep TypeScript - Readonly

am0wa
sumber
11

Angular 2 Menyediakan fitur yang sangat bagus yang disebut Konstanta Buram. Buat kelas & Tentukan semua konstanta di sana menggunakan konstanta buram.

import { OpaqueToken } from "@angular/core";

export let APP_CONFIG = new OpaqueToken("my.config");

export interface MyAppConfig {
    apiEndpoint: string;
}

export const AppConfig: MyAppConfig = {    
    apiEndpoint: "http://localhost:8080/api/"    
};

Suntikkan di penyedia di app.module.ts

Anda akan dapat menggunakannya di setiap komponen.

EDIT untuk Angular 4:

Untuk Angular 4 konsep baru adalah Token Injeksi & Token Tidak Berlaku dalam Angular 4.

Injeksi Token Menambahkan fungsi di atas Token Buram, memungkinkan untuk melampirkan info jenis pada token melalui generik TypeScript, ditambah token Injeksi, menghilangkan kebutuhan menambahkan @Inject

Kode Contoh

Sudut 2 Menggunakan Token Buram

const API_URL = new OpaqueToken('apiUrl'); //no Type Check


providers: [
  {
    provide: DataService,
    useFactory: (http, apiUrl) => {
      // create data service
    },
    deps: [
      Http,
      new Inject(API_URL) //notice the new Inject
    ]
  }
]

Sudut 4 Menggunakan Token Injeksi

const API_URL = new InjectionToken<string>('apiUrl'); // generic defines return value of injector


providers: [
  {
    provide: DataService,
    useFactory: (http, apiUrl) => {
      // create data service
    },
    deps: [
      Http,
      API_URL // no `new Inject()` needed!
    ]
  }
]

Token injeksi dirancang secara logis di atas Token buram & Token buram tidak digunakan lagi dalam Angular 4.

Parth Ghiya
sumber
6
tambah satu. Angular sama stabilnya dengan remaja berusia 13 tahun. mereka kehilangan fitur beberapa bulan setelah merilisnya. picik.
Stavm
1
kurang satu. Pertanyaan ini tidak ada hubungannya dengan Angular. Itu meminta solusi TypeScript.
Ben Nieting
4

Baik menggunakan pengubah readOnly dengan konstanta yang harus dideklarasikan atau orang mungkin mendeklarasikan konstanta di luar kelas dan menggunakannya secara khusus hanya di kelas yang diperlukan menggunakan operator get.

Krishna Ganeriwal
sumber
1

Untuk ini, Anda dapat menggunakan readonlypengubah. Properti objek yang readonlyhanya dapat ditugaskan selama inisialisasi objek.

Contoh di kelas:

class Circle {
  readonly radius: number;

  constructor(radius: number) {
    this.radius = radius;
  }

  get area() {
    return Math.PI * this.radius * 2;
  }
}

const circle = new Circle(12);
circle.radius = 12; // Cannot assign to 'radius' because it is a read-only property.

Contoh dalam Objek literal:

type Rectangle = {
  readonly height: number;
  readonly width: number;
};

const square: Rectangle = { height: 1, width: 2 };
square.height = 5 // Cannot assign to 'height' because it is a read-only property

Perlu juga diketahui bahwa readonlymodifikator adalah murni sebuah konstruksi naskah dan ketika TS dikompilasi ke JS, konstruksi tersebut tidak akan ada dalam JS yang dikompilasi. Ketika kita memodifikasi properti yang hanya dibaca, kompiler TS akan memperingatkan kita tentang hal itu (ini adalah JS yang valid).

Willem van der Veen
sumber
-2

Bagi saya tidak ada jawaban sebelumnya yang berfungsi. Saya memang perlu mengubah kelas statis saya menjadi enum. Seperti ini:

export enum MyConstants {
  MyFirstConstant = 'MyFirstConstant',
  MySecondConstant = 'MySecondConstant'
}

Kemudian di komponen saya, saya menambahkan properti baru seperti yang disarankan dalam jawaban lain

export class MyComponent {
public MY_CONTANTS = MyConstans;
constructor() { }
}

Kemudian dalam template komponen saya, saya menggunakannya dengan cara ini

<div [myDirective]="MY_CONTANTS.MyFirstConstant"> </div>

EDIT: Maaf. Masalah saya berbeda dari OP. Saya masih meninggalkan ini di sini jika seseorang memiliki masalah yang sama dengan saya.

Janne Harju
sumber
Menggunakan enum untuk menyimpan konstanta bukanlah praktik yang baik dalam bahasa apa pun.
Sangimed
Ini adalah solusi terbaik untuk solusi yang tersedia saat ini. Saya tahu itu adalah bagaimana enum tidak boleh digunakan tetapi dengan Angular itu adalah cara terbersih untuk memiliki konstanta yang dapat diikat.
Janne Harju