วิธีการใช้ค่าคงที่คลาสใน typescript ได้อย่างไร


429

ใน TypeScript constคำหลักไม่สามารถใช้เพื่อประกาศคุณสมบัติคลาส การทำเช่นนี้ทำให้คอมไพเลอร์เกิดข้อผิดพลาดด้วย "สมาชิกคลาสไม่สามารถมีคำหลัก 'const' ได้"

ฉันพบว่าตัวเองต้องการระบุอย่างชัดเจนในโค้ดว่าไม่ควรเปลี่ยนคุณสมบัติ ฉันต้องการ IDE หรือคอมไพเลอร์ผิดพลาดหากฉันพยายามกำหนดค่าใหม่ให้กับคุณสมบัติเมื่อมีการประกาศ พวกคุณประสบความสำเร็จได้อย่างไร

ขณะนี้ฉันใช้คุณสมบัติอ่านอย่างเดียว แต่ฉันใหม่กับ typescript (และ JavaScript) และสงสัยว่ามีวิธีที่ดีกว่า:

get MY_CONSTANT():number {return 10};

ฉันใช้ typescript 1.8 ข้อเสนอแนะ?

PS: ตอนนี้ฉันใช้ typescript 2.0.3 ดังนั้นฉันจึงยอมรับคำตอบของเดวิด

คำตอบ:


651

TypeScript 2.0 มีreadonlyตัวแก้ไข :

class MyClass {
    readonly myReadOnlyProperty = 1;

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

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

มันไม่แน่นอนเพราะอนุญาตให้กำหนดได้ในตัวสร้าง แต่นั่นไม่ใช่เรื่องใหญ่

ทางเลือกทางแก้ไข

อีกทางเลือกหนึ่งคือการใช้staticคำหลักด้วย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

สิ่งนี้มีประโยชน์ที่จะไม่สามารถกำหนดได้ในตัวสร้างและมีอยู่ในที่เดียวเท่านั้น


31
ในการเข้าถึงคุณสมบัติจากนอกคลาสคุณจะต้องเพิ่มexportคำหลักก่อนหน้าclassและpublic staticก่อนหน้าreadonlyคำหลัก ดูที่นี่: stackoverflow.com/a/22993349
cbros2008

คำถาม. clueless ทำไมคุณต้องใช้ชื่อคลาสเพื่อใช้คุณสมบัติ readOnly ภายในคลาสเอง? 'MyClass.myReadonlyProperty'
Saiyaff Farouk

@SaiyaffFarouk ถ้าฉันเข้าใจคำถามของคุณคำตอบก็คือคุณสมบัติแบบสแตติกมีอยู่เป็นส่วนหนึ่งของคลาสไม่ใช่ในอินสแตนซ์ของคลาส ดังนั้นคุณสามารถเข้าถึงได้โดยใช้ชื่อคลาสไม่ใช่ตัวแปรที่มีอินสแตนซ์ของคลาส
JeffryHouser

1
export(โมดูลภายนอก) และpublicคำหลักที่ไม่เกี่ยวข้องกับคำถามนี้ / คำตอบ แต่ในเรื่องของการชัดแจ้งที่ผมเองพบว่ามันง่ายมากที่จะบอกได้ว่าเป็นสมาชิกเป็นแบบสาธารณะเมื่อคำหลักไม่ได้อยู่ ฉันไม่สนใจมันด้วยเหตุผลนั้นและเพราะมันเพิ่มเสียงรบกวนมากกว่า & เป็นการพิมพ์ที่ไม่มีความจำเป็น นอกจากนี้ยังทำให้สมาชิกของประชาชนที่แตกต่างกันมากขึ้นจากคนที่ทำเครื่องหมายว่าเป็นหรือprivate protectedอย่างไรก็ตามความเห็นของฉัน :)
David Sherret

แล้วคลาสที่ไม่ระบุชื่อล่ะ? ความคิดเห็นเกี่ยวกับวิธีการเข้าถึงstatic readonly myReadOnlyPropertyเมื่อมีการประกาศคลาสด้วยexport default class { ... }? พยายามที่จะทำงานนี้ แต่ไม่ได้ทำงาน ... (แก้ไข: default.myVar ดูเหมือนจะเป็นวิธีการแก้ปัญหา แต่ฉันได้รับข้อผิดพลาดประเภท)
#:

67

ค่าคงที่สามารถประกาศนอกชั้นเรียนและใช้ภายในชั้นเรียนของคุณ มิฉะนั้นgetคุณสมบัติจะเป็นวิธีแก้ปัญหาที่ดี

const MY_CONSTANT: string = "wazzup";

export class MyClass {

    public myFunction() {

        alert(MY_CONSTANT);
    }
}

6
ขอบคุณ; ฉันกังวลเกี่ยวกับการใช้งานนี้เพราะมันไม่ได้พกพา (ในรูปแบบค่าคงที่ไม่ได้เป็นส่วนหนึ่งของชั้นเรียน) และมันรั่วไหลข้อมูลไปสู่ขอบเขตที่กว้างขึ้น แต่มันมีข้อดีของการเป็นค่าคงที่จริงดังนั้นฉันจึงชนะ ' ไม่สามารถเปลี่ยนได้โดยไม่ต้องยกระฆังปลุก
BeetleJuice

1
ฉันเข้าใจข้อกังวลใจและพบว่าการใช้งานgetทรัพย์สินนั้นเหมาะสมอย่างยิ่งในกรณีของคุณ
j3ff

3
ต่อangular.io/docs/ts/latest/guide/style-guide.htmlโปรดใช้อูฐ caase แทนตัวพิมพ์ใหญ่ ไม่แนะนำให้ใช้ตัวพิมพ์ใหญ่สำหรับค่าคงที่
Vadim Kirilchuk

12
styleguide เชิงมุมไม่ใช่ TypeScript styleguide .. คำถามเกี่ยวกับ TypeScript โดยเฉพาะ
VeldMuijz

4
@Esko ฉันเชื่อว่าใน typescript const จะถูก จำกัด ไว้ที่ไฟล์เพราะแต่ละไฟล์เป็นโมดูล เพื่อให้สามารถเข้าถึงได้จากภายนอกคุณจะต้องประกาศด้วยexport constแล้วนำเข้าจากไฟล์อื่น จะค่อนข้างง่ายต่อการทดสอบว่า เพียงประกาศconstไฟล์หนึ่งและลองใช้ไฟล์อื่นโดยไม่ส่งออก / นำเข้าหรือใช้จากคอนโซลเบราว์เซอร์
BeetleJuice


11

Angular 2 มีคุณสมบัติที่ดีมากที่เรียกว่า Opaque Constants สร้างคลาส & กำหนดค่าคงที่ทั้งหมดโดยใช้ค่าคงที่ทึบแสง

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/"    
};

ฉีดเข้าไปในผู้ให้บริการใน app.module.ts

คุณจะสามารถใช้งานได้กับทุกองค์ประกอบ

แก้ไขสำหรับเชิงมุม 4:

สำหรับ Angular 4 แนวคิดใหม่คือการฉีดโทเค็นและโทเค็นทึบแสงถูกคัดค้านใน Angular 4

หัวฉีดโทเค็นเพิ่มฟังก์ชันการทำงานที่ด้านบนของโทเค็นแบบทึบช่วยให้สามารถแนบข้อมูลประเภทบนโทเค็นผ่านข้อมูลทั่วไปของ TypeScript รวมถึงโทเค็นการฉีดทำให้ไม่ต้องเพิ่ม @Inject

รหัสตัวอย่าง

เชิงมุม 2 ใช้โทเค็นทึบแสง

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
    ]
  }
]

เชิงมุม 4 การใช้โทเค็นการฉีด

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!
    ]
  }
]

โทเค็นการฉีดได้รับการออกแบบอย่างมีเหตุผลที่ด้านบนของโทเค็นแบบทึบ & โทเค็นแบบทึบแสงถูกคัดค้านใน Angular 4


6
บวกหนึ่ง. เชิงมุมมีความเสถียรเท่ากับวัยรุ่นอายุ 13 ปี พวกเขาได้รับคุณสมบัติไม่กี่เดือนหลังจากปล่อยพวกเขา จิ๊บจ๊อย
Stavm

1
ลบหนึ่ง คำถามนี้ไม่เกี่ยวกับแองกูลาร์ มันกำลังร้องขอโซลูชั่น TypeScript
Ben Nieting

4

ทั้งใช้ readOnly โมดิฟายเออร์กับค่าคงที่จำเป็นต้องประกาศหรืออาจประกาศค่าคงที่นอกคลาสและใช้เฉพาะในคลาสที่ต้องการโดยใช้ตัวดำเนินการ get


1

สำหรับสิ่งนี้คุณสามารถใช้readonlyตัวแก้ไข คุณสมบัติของวัตถุที่readonlyสามารถกำหนดได้เฉพาะในช่วงเริ่มต้นของวัตถุ

ตัวอย่างในชั้นเรียน:

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.

ตัวอย่างใน Object literals:

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

นอกจากนี้ยังควรรู้ด้วยว่าreadonlyตัวดัดแปลงนั้นเป็นตัวสร้าง typescript อย่างหมดจดและเมื่อ TS ถูกคอมไพล์ไปยัง JS โครงสร้างจะไม่ปรากฏใน JS ที่คอมไพล์แล้ว เมื่อเรากำลังแก้ไขคุณสมบัติที่อ่านได้อย่างเดียวคอมไพเลอร์ TS จะเตือนเราเกี่ยวกับมัน (เป็น JS ที่ถูกต้อง)


-2

สำหรับฉันไม่มีคำตอบก่อนหน้านี้ทำงาน ฉันต้องการแปลงคลาสคงที่ของฉันเป็น enum แบบนี้:

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

จากนั้นในองค์ประกอบของฉันฉันเพิ่มคุณสมบัติใหม่ตามที่แนะนำในคำตอบอื่น ๆ

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

จากนั้นในเทมเพลตองค์ประกอบของฉันฉันใช้วิธีนี้

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

แก้ไข: ขออภัย ปัญหาของฉันแตกต่างจากของ OP ฉันยังคงออกจากที่นี่หากมีบางคนมีปัญหาเดียวกันกว่าฉัน


การใช้ enum เพื่อบันทึกค่าคงที่ไม่ใช่วิธีที่ดีในทุกภาษา
Sangimed

มันเป็นทางออกที่ดีที่สุดสำหรับโซลูชั่นที่มีอยู่ในปัจจุบัน ฉันรู้ว่ามันเป็นวิธีที่ enum ไม่ควรใช้ แต่ด้วย Angular มันเป็นวิธีที่สะอาดที่สุดในการมีค่าคงที่แบบ bindable
Janne Harju
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.