typescript - Arayüzdeki özellik tiplerinin birbirine bağlı olmasını nasıl sağlarım?
dataItem'in her zaman field özelliğinin değeri ile aynı türde olmasını sağlayacak dinamik bir yol bulamıyor gibiyim. Aşağıdaki örnekte dataItem her zaman string | Date | number olur, field özelliğinin ne olduğuna bağlı olarak belirli türde olmaz.
interface TableColumn<D> {
field: keyof D
renderCell: (dataItem: D[keyof D]) => ReactNode
}
interface Data {
foo: string
bar: Date
fiz: number
}
const data: Data = {
foo: "my foo",
bar: new Date(),
fiz: 32
}
const tableColumn: TableColumn<Data> = {
field: "foo",
renderCell: (dataItem) => dataItem // here dataItem should be string only
}
const tableColumn1: TableColumn<Data> = {
field: "bar",
renderCell: (dataItem) => dataItem // here dataItem should be Date only
}
const tableColumn2: TableColumn<Data> = {
field: "fiz",
renderCell: (dataItem) => dataItem // here dataItem should be number only
}
Cevap #1
Bir arayüz bu şekilde çalışmaz; muhtemelen bunu daha genel bir hale getirebilirsiniz, örneğin TableColumn<D, K> gibi, burada K, keyof D içindeki belirli bir anahtar türüdür, ancak o zaman K'yı her yerde belirtmeniz gerekecek.
Bunun yerine, TableColumn<D> öğesini, microsoft/TypeScript#47109'da adlandırıldığı gibi bir dağıtıcı nesne türü yapardım; bu tür, keyof T içindeki her K ile ilişkili bireysel türlerin birleşimine değerlendirilir. Dağıtıcı nesne türü, keyof D içindeki her özellik değerini, ilgili özellik anahtarına karşılık gelen istenen türü tutan bir tipe dönüştüren ve ardından hemen keyof D ile indekslenen bir eşlenen türdür. Şöyle:
type TableColumn<D> = { [K in keyof D]-?:
{
field: K,
renderCell: (dataItem: D[K]) => ReactNode
}
}[keyof D]
Burada, { [K in keyof D]-?: { field: K, renderCell: (dataItem: D[K]) => ReactNode }} eşlenen türünü üretiyoruz, bu Data için şuna benzer bir şey olur
{
foo: { field: "foo"; renderCell: (dataItem: string) => ReactNode }
bar: { field: "bar"; renderCell: (dataItem: Date) => ReactNode }
fiz: { field: "fiz"; renderCell: (dataItem: number) => ReactNode }
}
Dikkat edin, -? eşleme değiştiricisi, D içindeki herhangi bir isteğe bağlı özelliğin eşlenen türde zorunlu hale gelmesini sağlar, çünkü burada herhangi bir undefined değerin dolaşmasını istemeyiz.
Sonra buna {...}[keyof D] üzerinden indeksleme yapıyoruz, bu da o eşlenmiş türü değer türlerinin bir birleşimi haline getiriyor ve sonunda şunu üretiyor:
type TCD = TableColumn<Data>
/* type TCD = {
field: "foo";
renderCell: (dataItem: string) => ReactNode;
} | {
field: "bar";
renderCell: (dataItem: Date) => ReactNode;
} | {
field: "fiz";
renderCell: (dataItem: number) => ReactNode;
} */
İşte istediğiniz birleşim türü; aslında, field özelliğinin ayırt edici özellik olduğu bir ayrılmış birleşimdir. Bu, derleyicinin field türünden renderCell türünü çıkarmasını sağlar ve böylece renderCell’in açıklanmamış geri arama parametresinde istediğiniz bağlamsal türlemeyi verir:
const tableColumn: TableColumn<Data> = {
field: "foo",
renderCell: (dataItem) => dataItem
// (parameter) dataItem: string
}
const tableColumn1: TableColumn<Data> = {
field: "bar",
renderCell: (dataItem) => dataItem
// (parameter) dataItem: Date
}
const tableColumn2: TableColumn<Data> = {
field: "fiz",
renderCell: (dataItem) => dataItem
// (parameter) dataItem: number
}
Koda yönelik oyun alanı bağlantısı
