typescript - ฟังก์ชันการแมปวัตถุแบบทั่วไปพร้อมประเภทการคืนค่าที่ถูกต้อง
ดังนั้นโดยพื้นฐานแล้วฉันมีข้อมูลที่ส่งเข้ามาจากอีกอันผ่านคำขอแบบโพสต์ในวัตถุขนาดใหญ่ ฉันจำเป็นต้องดึงบางฟิลด์ออกมาและใส่ลงในวัตถุที่เฉพาะเจาะจงมากขึ้นโดยมีบางฟิลด์ของพวกมันถูกแมปใหม่ เพื่อนำไปแทรกลงในฐานข้อมูล
ฉันมีสิ่งนี้ที่ทำงานในแบบที่ไม่ใช่แบบทั่วไป แต่ฉันอยากมีฟังก์ชันที่ทั่วไปมากขึ้น แต่ยังคงปลอดภัยต่อชนิดข้อมูลอย่างสมบูรณ์
นี่คือเวอร์ชันลดขนาดของโค้ดเท่าที่ฉันมีในตอนนี้
import type { O } from 'ts-toolbelt';
const userFields = {
accountFirstName: 'firstName',
accountLastName: 'lastName',
email: 'email',
cellphone: 'cellPhone',
city: 'city',
state: 'state',
street: 'street',
zip: 'zip',
} as const;
const playerFields = {
playerId: 'sc_id',
playerFirstName: 'firstName',
playerLastName: 'lastName',
sizingJersey: 'jerseySize',
sizingShorts: 'shortSize',
} as const;
const allFields = {
...userFields,
...playerFields
}
type EventData = typeof allFields;
type InvertedRecord<R extends { [P in keyof R]: R[P]; }> = Record<keyof O.Invert<R>, string>;
type UserRecord = InvertedRecord<typeof userFields>
function objectKeys<Obj> (obj: Obj): (keyof Obj)[] {
return Object.keys(obj) as (keyof Obj)[];
};
// take just the user fields from the full data object and put them into a new object
const extractUser = (data: EventData) => {
const user: Partial<UserRecord> = {};
objectKeys(userFields).forEach((field) => {
user[allFields[field]] = data[field];
});
return user as UserRecord;
};
// A more generic extract function that takes the list of fields and the data object and extracts the fields into a new object
function genericExtract <T>(fields: T, data: EventData): T {
const obj: Partial<T> = {};
objectKeys(userFields).forEach((field) => {
obj[allFields[field]] = data[field]; // <--- obj's type doesn't get properly inferred so the assignment is not compatible
});
return obj as T;
}
ลิงก์ TS Playground สำหรับข้อมูลเพิ่มเติมเกี่ยวกับปัญหาที่เกี่ยวข้อง
ลิงก์สนามเด็กเล่นที่สอง
คำตอบ #1
อันดับแรก ชนิดง่ายๆ เพื่อรับค่าของชนิดอ็อบเจ็กต์:
type Values<T> = T[keyof T];
ปัญหาคือ T ใน genericExtract ไม่มีข้อจำกัด ซึ่งหมายความว่า allFields[field] ไม่จำเป็นต้องเป็นกุญแจของ T นี่คือเหตุผลที่คุณได้รับข้อผิดพลาด
ในการแก้ปัญหานี้ ให้เพิ่มข้อจำกัดไปที่ T:
function genericExtract <T extends Record<Values<typeof allFields>, unknown>>(fields: T, data: EventData): T {
สนามเด็กเล่น
