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

typescript - ดึงประเภทของคุณสมบัติจาก oneof


ฉันมีประเภท A ดังนี้:

type OneOf =
  | {
      $case: 'one';
      one: One;
    }
  | {
      $case: 'two';
      two: Two;
    }
  | {
      $case: 'three';
      three: Three;
    };

ฉันต้องการสร้างประเภทใหม่เพื่อให้สามารถรับจากอินพุต OneOf และรับผลลัพธ์เป็น One | Two | Three ได้

ฉันได้ลองหลายวิธีต่าง ๆ รวมถึงวิธีหนึ่งจากคำตอบนี้ที่มี UnionToIntersection ด้วยความหวังว่าด้วยการหาภาพตัดกัน ฉันจะสามารถยกเว้น $case ได้ง่าย ๆ ลูปผ่านคีย์และส่งคืนชนิดข้อมูล

ฉันมักจะได้ประเภท never เป็นผลลัพธ์เสมอ

โดยพื้นฐานแล้ว ฉันคิดว่าฉันสามารถหลีกเลี่ยงได้ด้วยสิ่งต่อไปนี้:

type ExtractOneOfTypes<T, K extends keyof T = keyof T> = {
  [key in K]: T extends { $case: key } ? T[key] : never;
}[K];

เพราะใน oneOf ของฉัน สำหรับแต่ละ $case บนวัตถุเดียวกันนั้นมีชื่อคุณสมบัติที่ตรงกับค่าของ $case แต่สิ่งนี้ใช้ไม่ได้ มีไอเดียไหม?

คำตอบ #1

คุณสามารถ อนุมาน ประเภทค่าตัวอักษรของ $case แล้วตรวจสอบว่ามันเป็น keyof T หรือไม่ โดยใช้ประเภทเชิงเงื่อนไขซ้อนกันดังนี้:

type One = { one: string };
type Two = { two: number };
type Three = { three: boolean };

type OneOf =
  | { $case: "one"; one: One }
  | { $case: "two"; two: Two }
  | { $case: "three"; three: Three };

type ExtractOneOfTypes<T, K extends keyof T> = T extends { [Key in K]: infer U }
  ? U extends keyof T
    ? T[U]
    : never
  : never;

type ExtractedType = ExtractOneOfTypes<OneOf, "$case">;
//    ^? type ExtractedType = One | Two | Three

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