Typecript 2D değişken şablonu
Şu anda bir numaralandırma ile belirlenebilen başka bir arabirim türünün bir veri üyesini kullanan bir arabirimim var:
enum E { a, b, c }
interface E2Data {
[E.a]: { a: string },
[E.b]: { b: string },
[E.c]: { c: string }
}
interface A<T extends E[] = E[]> {
data: { [i in keyof T]: T[i] extends E ? E2Data[T[i]] : never }
}
// Can give the enums in the template, and get autocomplete in the data.
let a1: A<[E.a, E.b]> = {
data: [{ a: "" }, { b: "" }]
};
// Or can get autocomplete with type assertion on elements.
// Ideally this would infer template types too, but apparently not.
let a2: A = {
data: [ <E2Data[E.a]>{ a: "" }, <E2Data[E.b]>{ b: "" } ]
}
Anladığıma göre, artık a1.datave a2.datadiziler olarak kullanabilirim , ancak a1.dataher bir öğenin türünü bilirim (yani aslında bir demet?)
Şimdiinterface A verileri için 2B bir dizi kullanmak istiyorum .
Aşağıdakilerin işe yarayacağını düşündüm, ancak E2Datakullanarak indekslememe izin vermezdi T[i][j].
interface B<T extends E[][] = E[][]> {
data: {
[i in keyof T]:
T[i] extends E[] ? {
[j in keyof T[i]]:
T[i][j] extends E ? E2Data[T[i][j]] : never }
// ^^^^^^^^^^^^^^^
// Type 'T[i][j]' cannot be used to index type 'E2Data'.
: never
}
}
Şu anki çözümüm bir tür birleşimi kullanmak, ancak bu, bir şablon kullanarak istediğim verileri belirlememe izin vermiyor.
interface B {
data: (E2Data[E.a] | E2Data[E.b] | E2Data[E.c])[][];
}
dataYukarıda 2B bir dizi için açıklandığı gibi 2 otomatik tamamlama yöntemini desteklemenin bir yolu var mı ?
let b1: A<[ [E.a], [E.b] ]> = {
data: [ [{ a: "" }], [{ b: "" }] ]
}
let b2: A = {
data: [ [<E2Data[E.a]>{ a: "" }], [ <E2Data[E.b]>{ b: "" }] ]
}
Yanıtlar
Bu biraz düşünmemi sağladı, ancak çözüm aslında oldukça basit çünkü ayak işlerinin çoğunu orijinalinizle zaten yaptınız interface A.
Genel DataArrayolarak E değerlerinin bir demetini alan ve karşılık gelen E2Data'nın bir demetini döndüren genel bir tür tanımlayın . DataArrayMantığı içerecek ve Aonu kullanacak şekilde yeniden biçimlendirebilirsiniz , ancak basitlik için sadece mevcut mantığa erişelim A.
type DataArray<T extends E[]> = A<T>['data'];
İçinde iç içe geçmiş bir dizin imzası kullanmak yerine, interface Btek bir dizin imzası kullanabilir DataArrayve iç dizileri oluşturmak için türü çağırabilirsiniz .
interface B<T extends E[][] = E[][]> {
data: {
[i in keyof T]: T[i] extends E[] ? DataArray<T[i]> : never
}
}
Artık E'yi karıştırıp eşleştirerek herhangi bir 2D veri türü oluşturursunuz.
let b: B<[[E.a], [E.b, E.c]]> = {
data: [ [{ a: "" }], [{ b: "" }, {c: ""}] ]
}
Düzenleme Bunu istemediğinizi biliyorum, ama burada daha derinlemesine iç içe geçmiş değerlerle nasıl başa çıkacağınız anlatılmaktadır. ( Özyinelemeli diziler hakkında bu yanıttan biraz rehberlik ederek ).
interface Nested<T> extends Array<Nested<T> | T> {
}
type NestedData<T extends Nested<E>> = {
[i in keyof T]: T[i] extends E ? E2Data[T[i]] : T[i] extends Nested<E> ? NestedData<T[i]> : never
}
interface C<T extends Nested<E>> {
data: NestedData<T>
}
let c: C<[E.a, [E.b, [E.c]]]> = {
data: [ { a: "" }, [{ b: "" }, [{c: ""}] ]]
}