Hur refererar du till en objektsgränssnitts nyckel i dess värde med Typescript?
Jag försöker skapa ett objektgränssnitt (transforms), som har nycklar som är egenskaper hos ett generiskt objekt (T), så att nycklarna kan mappas till en funktion som skickar egenskapsvärdet av T specifikt för den nyckel den skickades till.
interface Options<T> {
headers: (keyof T)[]
filename: string
items: T[]
transforms?: Partial<{
[field in T as keyof T]: (item: T[field extends keyof T ? field : never]) => string
}>
}
Just nu löses item alltid till never. Jag vill att det ska kunna lösas till T[field] eller snarare T[keyof T] specifikt för den nyckel det är kopplat till.
REDIGERA
Här är ett bättre exempel på vad jag försökte åstadkomma. Jag försöker säkerställa att argumenten som skickas till funktionerna i transforms-objektet, vilka har nycklar som är egenskaper av T, har korrekt typ (T[keyof T]). I det korrigerade exemplet nedan bör color vara en sträng, och isTasty bör vara en boolean när de skickas som argument i "transforms".
interface Food {
isTasty: boolean
color: string
}
interface Options<T> {
headers: (keyof T)[]
filename: string
items: T[]
transforms?: Partial<{
?
}>
}
function Foo<T>({headers, filename, items, transforms}: Options<T>){
return 'bar'
}
Foo({
headers: ['isTasty', 'color'],
filename: 'test',
items: [{color: 'red', isTasty: true}] as Food[],
transforms: {
color: (color) => '#' + color,
isTasty: (isTasty) => isTasty ? 'Yes' : 'No'
}
})
fast och fungerande exempel
Svar #1
Du vill bara att transforms-egenskapen ska vara en mappad typ över egenskaperna i T. Att skriva {[K in keyof T]: F<K>} kommer att skapa en ny typ med samma nycklar som T, men vars egenskaper är F<K> för varje nyckeltyp K. I ditt fall vill du att varje egenskap ska vara en funktion som accepterar ett värde av typen som motsvarar egenskapsvärdet i T vid nyckeln K. Det vill säga, en funktion som accepterar ett värde av den indexerade access-typen T[K]. Så här:
{ [K in keyof T]: (property: T[K]) => string }
Observera att om du vill använda Partial<T>-verktygstypen på det, kan du skriva detta enklare med den valfria mappingsmodifieraren (?):
{ [K in keyof T]?: (property: T[K]) => string }
Det ger dig följande definition för Options<T>:
interface Options<T> {
headers: (keyof T)[]
filename: string
items: T[]
transforms?: {
[K in keyof T]?: (property: T[K]) => string
}
}
Och sedan fungerar allt som du vill:
function foo<T>(o: Options<T>) { }
foo({
headers: ['isTasty', 'color'],
filename: 'test',
items: [{ color: 'red', isTasty: true }],
transforms: {
color: (color) => '#' + color,
isTasty: (isTasty) => isTasty ? 'Yes' : 'No'
}
})
Lekplatslänk till kod
