Güvenli varyantlar
Güvenlik derleme zamanı kontrolleriyle bir arabirimden bir anahtar dizisi veya demeti oluşturmak biraz yaratıcılık gerektirir. Türler çalışma zamanında silinir ve nesne türleri (sırasız, adlandırılmış) desteklenmeyen tekniklere başvurulmadan tuple türlerine (sıralı, adsız) dönüştürülemez .
Diğer cevaplarla karşılaştırma
Burada önerilen varyantların tümü, gibi bir referans nesne türü verilen yinelenen veya eksik tuple öğeleri olması durumunda bir derleme hatasını dikkate alır / tetikler IMyTable. Örneğin bir dizi türü bildirmek (keyof IMyTable)[]bu hataları yakalayamaz.
Ek olarak, belirli bir kitaplık gerektirmezler ( ts-morphgenel bir derleyici sarmalayıcısı olarak düşüneceğim son varyant kullanımları ), bir nesnenin aksine bir tuple türü yayınlarlar (yalnızca ilk çözüm bir dizi oluşturur) veya geniş dizi türü (ile karşılaştırıldığında bu cevaplar ) ve son olarak derslere ihtiyaç duymaz .
Varyant 1: Basit tipli dizi
function createKeys(keyRecord: Record<keyof IMyTable, any>): (keyof IMyTable)[] {
return Object.keys(keyRecord) as any
}
const keys = createKeys({ isDeleted: 1, createdAt: 1, title: 1, id: 1 })
++-otomatik tamamlama -dizisi ile en kolay kılavuz , tuple yok
Oyun alanı
Bir kayıt oluşturmayı sevmiyorsanız, bu alternatife Setve onaylama türlerine bir göz atın .
Varyant 2: Yardımcı işlevli Tuple
function createKeys<T extends readonly (keyof IMyTable)[] | [keyof IMyTable]>(
t: T & CheckMissing<T, IMyTable> & CheckDuplicate<T>): T {
return t
}
++-Otomatik tamamlama +-daha gelişmiş, karmaşık türlerle demet kılavuzu
Oyun alanı
Açıklama
createKeysuygun olmayan girdi için bir hata veren fonksiyon parametre tipini ek onaylama tipleriyle birleştirerek derleme zamanı kontrolleri yapar . (keyof IMyTable)[] | [keyof IMyTable]bu , aranan taraftaki bir dizi yerine bir dizinin çıkarımını zorlamanın "kara büyü" yoludur . Alternatif olarak, sabit iddiaları /as const arayan tarafından kullanabilirsiniz.
CheckMissingkontroller, Tanahtarları kaçırırsa U:
type CheckMissing<T extends readonly any[], U extends Record<string, any>> = {
[K in keyof U]: K extends T[number] ? never : K
}[keyof U] extends never ? T : T & "Error: missing keys"
type T1 = CheckMissing<["p1"], {p1:any, p2:any}>
type T2 = CheckMissing<["p1", "p2"], { p1: any, p2: any }>
Not: T & "Error: missing keys"sadece güzel IDE hataları içindir. Sen de yazabilirsin never. CheckDuplicatesçift tuple öğelerini kontrol eder:
type CheckDuplicate<T extends readonly any[]> = {
[P1 in keyof T]: "_flag_" extends
{ [P2 in keyof T]: P2 extends P1 ? never :
T[P2] extends T[P1] ? "_flag_" : never }[keyof T] ?
[T[P1], "Error: duplicate"] : T[P1]
}
type T3 = CheckDuplicate<[1, 2, 3]>
type T4 = CheckDuplicate<[1, 2, 1]>
Not: Tuplelardaki benzersiz öğe kontrolleri hakkında daha fazla bilgi bu yayında . İle TS 4.1 , biz de hata dizesi eksik tuşları adlandırabilirsiniz - bakmak bu Oyun .
Varyant 3: Özyinelemeli tür
TypeScript 4.1 sürümüyle birlikte, potansiyel olarak burada da kullanılabilecek koşullu özyinelemeli türleri resmi olarak destekler . Tür hesaplaması, kombinasyon karmaşıklığı nedeniyle pahalıdır - performans 5-6'dan fazla öğe için büyük ölçüde azalır. Bu alternatifi eksiksizlik için listeliyorum ( Playground ):
type Prepend<T, U extends any[]> = [T, ...U]
type Keys<T extends Record<string, any>> = Keys_<T, []>
type Keys_<T extends Record<string, any>, U extends PropertyKey[]> =
{
[P in keyof T]: {} extends Omit<T, P> ? [P] : Prepend<P, Keys_<Omit<T, P>, U>>
}[keyof T]
const t1: Keys<IMyTable> = ["createdAt", "isDeleted", "id", "title"]
++-otomatik tamamlama ile tuple kılavuzu +yardımcı fonksiyon --performansı yok
Varyant 4: Kod oluşturucu / TS derleyici API'si
ts-morph , orijinal TS derleyici API'sine biraz daha basit bir sarmalayıcı alternatifi olduğundan burada seçilmiştir . Elbette, derleyici API'sini doğrudan da kullanabilirsiniz. Jeneratör koduna bakalım:
import {Project, VariableDeclarationKind, InterfaceDeclaration } from "ts-morph";
const project = new Project();
const sourceFile = project.addSourceFileAtPath("./src/IMyTable.ts");
const destFile = project.createSourceFile("./src/generated/IMyTable-keys.ts", "", {
overwrite: true
});
function createKeys(node: InterfaceDeclaration) {
const allKeys = node.getProperties().map(p => p.getName());
destFile.addVariableStatement({
declarationKind: VariableDeclarationKind.Const,
declarations: [{
name: "keys",
initializer: writer =>
writer.write(`${JSON.stringify(allKeys)} as const`)
}]
});
}
createKeys(sourceFile.getInterface("IMyTable")!);
destFile.saveSync();
Bu dosyayı derleyip çalıştırdıktan sonra aşağıdaki içeriğe sahip tsc && node dist/mybuildstep.jsbir dosya ./src/generated/IMyTable-keys.tsoluşturulur:
const keys = ["id","title","createdAt","isDeleted"] as const;
+otomatik olarak oluşturma solüsyonu +birden çok özellik için ölçeklenebilir +bir yardımcı işlev +demet -ilave yapı adım -derleyici API ile benzerlik ihtiyacı