TypeScript'te, herhangi bir türdeki bir değeri özel bir türe dönüştürmek ve değer eşleşmediğinde varsayılan bir değer kullanmak mümkün müdür?


Diyelim ki şöyle bir türüm var

type MyType = "value1" | "value2"

ve benim bir any türünde x adlı bir değerim var. x değeri MyType türüne uymuyorsa bazı belirli bir varsayılan değer d döndürecek şekilde x'i MyType'a zorlamak için bir yol var mı ve böylece TS derleyicisi bunu tür olarak kontrol edebilsin?
Şuna benzer bir şey:

let y: MyType = magicThatDoesWhatIWant(x, MyType, d)

Bu, derleme sonrasında aşağıdaki JS koduna benzeyen bir şey üretecektir:

let y;
switch (x) {
  case "value1":
     y = x
     break;
  case "value2":
     y = x
     break;
  default:
     y = d
}

TS'de bunun gibi bir şey var mı?

Cevap #1

Aradığınız şey, bir any değişkenin türünü doğrulamak için kullanıcı tanımlı bir tür koruyucusudur. Bunu, bir yedek değer atanmasıyla birleştirebilirsiniz.

MyType'i bir fonksiyona argüman olarak geçiremezsiniz çünkü TypeScript türleri çalışma zamanında mevcut değildir, bu yüzden değişken olarak kullanılamazlar. İstediğinizi, eğer MyType bir değişkenden türetilmişse başarabilirsiniz; çünkü o değişkeni çalışma zamanında kontrol için kullanabilirsiniz.

Bir Dizi'den

Kendi türümüzün değerleriyle değiştirilemez bir sabit tanımlarız:

const strings = [ "value1", "value2" ] as const;

Şöyle deriz: MyType, o dizinin elemanlarının türüdür:

type MyType = (typeof strings)[number];

Bu bizim tip koruyucumuzdur. Eğer any değişkeni x, tüm değerlerin tipi T olan bir dizide bulunuyorsa, o zaman x'in tipinin T olduğunu doğrularız.

function isInArray<T>(x: any, values: readonly T[]): x is T {
    return values.includes(x);
}

Şimdi sizin "sihir"iniz için. Kontrol etmek için bir values dizisi ve ayrıca bir varsayılan değer d geçirmeliyiz. Döndürdüğümüz değerin türünün T olduğunu bileceğiz.

function castToType<T>(x: any, values: readonly T[], d: T): T {
    return isInArray(x, values) ? x : d;
}

Bu örnekte hem v1 hem de v3 "value1" | "value2" türüne sahiptir. v1 "value1"dir çünkü bu dize türümüzle eşleşti. v3 ise varsayılan olan "value2"dir.

const v1 = castToType("value1", strings, "value2")
const v3 = castToType("value3", strings, "value2")

Typescript Oynatma Alanı Bağlantısı

Bir Enum'dan

Dizi yöntemi herhangi bir birleşim türü ile çalışır. Değerleriniz string veya number ise, bunlar hem tür bildirimi hem de çalışma zamanında kullanabileceğimiz bir nesne değişkeni oluşturduğundan TypeScript enum'larından yararlanabilirsiniz.

enum MyEnum {
    Value1 = "value1",
    Value2 = "value2",
}

Temelde aynı şekilde kontrol ediyoruz, tek fark Object.values kullanarak geçerli enum değerlerinden bir dizi elde etmemiz.

function isInEnum<T>(x: any, enumObj: Record<string, T>): x is T {
    return Object.values(enumObj).includes(x);
}

function castToType<T>(x: any, enumObj: Record<string, T>, d: T): T {
    return isInEnum(x, enumObj) ? x : d;
}

const v1 = castToType("value1", MyEnum, MyEnum.Value2)
const v3 = castToType("value3", MyEnum, MyEnum.Value2)

Typescript Oynatma Alanı Bağlantısı