ค้นหาเว็บไซต์

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 {

สนามเด็กเล่น