reactjs - Nyckel som en del av ett större objekt
Jag har följande typ:
type FormData = {
field1: string;
field2: string;
fieldₙ: string;
}
Jag vill skapa en funktion för React som endast tar emot en nyckel och ett värde, där nyckeln är en av de i den tidigare typen (FormData).
Så, i det här fallet vill jag skapa en typ som kan omsluta följande:
{field1: string} eller {field2: string} och alla andra möjliga fält.
Grundläggande idén är att kunna skriva en funktion som denna:
(data: {field from FormData: string}): void
Finns det något sätt att skapa en typ som denna?
Jag försökte använda [key in FormData]:string, men det tvingar mig att ha alla fält, och inte bara ett.
Jag vill inte göra dem alla ignorerbara med ?.
Svar #1
Du kan använda en självindexerande mappad typ på följande sätt:
type Data = { field1: string; field2: string; fieldₙ: string; };
type DataField = { [K in keyof Data]: { [SK in K]: Data[K] } }[keyof Data];
Vilket ger dig följande resultattyp:
type DataField = {
field1: string;
} | {
field2: string;
} | {
fieldₙ: string;
}
Svar #2
Något liknande detta? Observera att det stöder olika värdetyper för fälten, och det resulterande objektet är också typat.
type FormData = {
field1: string;
field2: number;
field3: boolean;
};
function getSingleField<K extends keyof FormData>(
key: K,
formData: FormData
): { [P in K]: FormData[P] } {
return { [key]: formData[key] } as { [P in K]: FormData[P] };
}
// Example usage
const formData: FormData = {
field1: "What's the answer?",
field2: 42,
field3: true,
};
const singleField = getSingleField("field2", formData);
console.log(singleField); // { field2: 42 }
Redigera 1: När jag tänker på det, skulle detta problem kunna abstraktas till en generisk typ, och inte begränsas till FormData eller en specificerad typ:
function getField<K extends keyof T, T>(
key: K,
data: T
): { [P in K]: T[P] } {
return { [key]: data[key] } as { [P in K]: T[P] };
}
const exampleData = { a: "hello", b: 123 }
const b = getField("b", exampleData);
console.log(b); // { b: 123 }
Redigera 2: Logiken kan vidareutvecklas till vilket antal nycklar som helst från vilken objekttyp som helst:
export function getFields<K extends keyof T, T>(
keys: K[] | K,
data: T
): { [P in K]: T[P] } {
if (!Array.isArray(keys)) { return getField(keys, data); }
return keys.reduce((result, key) => {
result[key] = data[key];
return result;
}, {} as { [P in K]: T[P] });
}
const exampleData = {
a: "hello",
b: 123,
c: true,
d: ["array", "of", "strings"],
};
const a_and_d = getFields(["a", "d"], exampleData);
console.log(a_and_d); // { a: "hello", d: ["array", "of", "strings"] }
const just_c = getFields("c", exampleData);
console.log(just_c); // { c: true }
