String'i TypeScript'te doğrulama ile const enum'a dönüştür
Aşağıdaki gibi bir const enum'um var:
const enum Color {
Red = "red",
Green = "green",
Blue = "blue"
}
Benim de dışarıdan gelen bazı bir string’im var (diyelim ki, colorString). Değeri ya "red", ya "green", ya da "blue" olmalı, ama bu kesin değil. Bunu doğrulamak ve geçersiz bir değer durumunda hata fırlatmak istiyorum.
‘dönüşüm’ için, sadece şunu yapabilirim:
const color: Color = colorString as Color;
Bu stringi enum'a 'dönüştürür', ama doğrulamaz. Eğer constString === "purple" ise çalıştırma sırasında herhangi bir hata olmayacaktır. Doğrulama için, şunu yapabilirim:
function stringToColor(colorString: string): Color {
switch (colorString) {
case Color.Red:
case Color.Green:
case Color.Blue:
return colorString; // no need to do 'as', TS knows that colorString is valid Color enum value
default:
throw new Error(`Invalid color ${colorString}.`);
}
}
Bu, string'i enum'a 'dönüştürür' ve doğrular, ancak biraz uzun ve hata yapmaya elverişli. Örneğin, Color enum'una yeni bir değer eklersem, kodumun düzgün çalışabilmesi için stringToColor fonksiyonundaki switch ifadesine yeni bir case eklemem gerekecek.
Bildiğim kadarıyla, const enum'lar sadece derleme zamanında vardır ve çalışma zamanında tamamen düz stringlere dönüştürülür. Yani gerçek bir dönüşüm yoktur. Üstelik, Object.values(Color) yapamam, çünkü Color bir const enum ve çalışma zamanında mevcut değildir. Aslında ihtiyacım olan şudur:
- dizenin belirlenmiş (geçerli) değerlerden birine sahip olup olmadığını çalıştırma zamanında kontrol etmek;
- TypeScript'e bir string'in derleme zamanında enum olarak temsil edilebileceğini söylemek.
Bir diğer çözüm, tüm geçerli değerleri bu şekilde bir nesnede tutmaktır:
const colors: { readonly [color in Color]: color } = {
[Color.Red]: Color.Red,
[Color.Green]: Color.Green,
[Color.Blue]: Color.Blue,
};
Buradaki iyi taraf şu ki, bu nesne her enum değeri için bir özelliğe sahip olmalıdır (Color[]'ın aksine). Enum'a yeni bir değer eklersem, ama bunu colors nesnesine eklemeyi unutursam, derleme zamanında hata verir. Bu yüzden, sadece birkaç case ifadesi yazmaktan daha az hata yapmaya meyillidir. Sonra şunu yapabilirdim:
function stringToColor(colorString: string): Color | undefined {
return Object.values(colors).find((value) => colorString === value);
}
Geçersiz değer durumunda undefined döner, bu kabul edilebilir.
Ancak, daha az kelimeyle ve daha zarif çözümler olup olmadığını merak ediyorum.
Cevap #1
Eğer programınızın başka bir yerinde Color enum'ını kullanıyorsanız ve kullanmaya devam etmek istiyorsanız, maalesef yapmak istediğiniz şey için zarif bir çözüm yok. Buraya bir göz atın.
Ama, başarmak istediğiniz şeyi başarmanın neredeyse zarif bir yolu var, o da aşağıdaki gibi bir nesne kullanmaktır:
const Color = {
Red: "red",
Green: "green",
Blue: "blue"
} as const
const func = (color: typeof Color[keyof typeof Color]) => {
console.log(color);
}
func("blue") // okay!
func("purple") // Argument of type '"purple"' is not assignable to parameter of type '"red" | "green" | "blue"'
Dezavantajı, Color'ı enumlar gibi bir tip olarak kullanamamanızdır; bunun için typeof Color'ı kullanmanız gerekir.
