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 }