การแมปประเภททูเพิลภายในประเภททูเพิล

เอกสารสำหรับ ประเภททูเพิลที่แมป เสนอตัวอย่างนี้:

type MapToPromise<T> = { [K in keyof T]: Promise<T[K]> };

type Coordinate = [number, number]

type PromiseCoordinate = MapToPromise<Coordinate>; // [Promise<number>, Promise<number>]

แต่จะเกิดอะไรขึ้นถ้าทูเปิลดั้งเดิมของฉันมีสิ่งอันดับอื่นๆ และในฐานะส่วนหนึ่งของการแมป ฉันต้องการดึงค่าที่น่าสนใจออกจากทูเปิลภายในเหล่านั้น

e.g.

// I just want the numbers, but there is other stuff in the type
type MessyCoordinate = [
    [string, number],
    [string, number]
]

ฉันคาดหวังว่าฉันจะทำสิ่งนี้ได้:

type Clean<T extends [string, number]> = T[1]

// Why doesn't this work?
type MapToClean<T> = { [K in keyof T]: Clean<T[K]> }

type CleanCoordinate = MapToClean<MessyCoordinate>; // [number, number]

คอมไพเลอร์ให้ข้อผิดพลาดนี้แก่ฉัน:

Type 'T[K]' does not satisfy the constraint '[string, number]'.
  Type 'T[keyof T]' is not assignable to type '[string, number]'.
    Type 'T[string] | T[number] | T[symbol]' is not assignable to type '[string, number]'.
      Type 'T[string]' is not assignable to type '[string, number]'.(2344)

ฉันสามารถลองเพิ่มข้อจำกัดเพิ่มเติมใน MapToClean ได้ แต่ดูเหมือนจะไม่ช่วยอะไร:

type MapToClean2<T extends [string, number][]> = { [K in keyof T]: Clean<T[K]> }

ฉันยังสามารถกำจัดประเภทยูทิลิตี้ Clean ได้ด้วยและทำสิ่งนี้ แต่มันก็ไม่ได้ผลเช่นกัน:

// Why doesn't this work?
type MapToClean<T> = { [K in keyof T]: T[K][1] }
// Type '1' cannot be used to index type 'T[K]'.

type CleanCoordinate = MapToClean<MessyCoordinate>; // [number, number]

ความคาดหวังพื้นฐานของฉันที่ฉันควรจะสามารถเปิดทูเพิลในการแมปนั้นมีข้อบกพร่องหรือไม่ หรือฉันแค่ขาดไวยากรณ์เล็กน้อยเพื่อให้ T[K] ดูเหมือน [string, number]

ลิงค์สนามเด็กเล่น


person Matt Wynne    schedule 05.06.2020    source แหล่งที่มา


คำตอบ (2)


ปัญหาที่ชัดเจนที่นี่คือ T ใน MapToClean<T> ไม่ได้ ถูกจำกัด เป็นประเภทที่มีคุณสมบัติเป็น [string, number] คุณสามารถเพิ่มข้อจำกัดที่เหมาะสมได้ จากนั้นมันจะได้ผล:

type MapToClean<T extends { [K in keyof T]: [string, number] }> =
    { [K in keyof T]: Clean<T[K]> }

ปัญหาที่ชัดเจนน้อยกว่าคือเหตุใดข้อจำกัดที่ต้องการ T ให้เป็นประเภทอาร์เรย์โดยเฉพาะจึงยังคงล้มเหลว:

type MapToCleanOops<T extends [string, number][]> =
    { [K in keyof T]: Clean<T[K]> } // same error

นั่น ปัญหาคือจุดบกพร่องที่โดดเด่นใน TypeScript microsoft/TypeScript#27995< /ก>. เมื่อคุณแมปบนทูเพิลด้วยประเภทแมป คุณจะได้สิ่งทูเพิลออกมา แต่คอมไพเลอร์ไม่ทราบว่าภายในคำจำกัดความของประเภทที่แมป: ดู สิ่งนี้ ความคิดเห็น. สำหรับตอนนี้ วิธีแก้ปัญหาคือต้องทำบางอย่างเพื่อแจ้งให้คอมไพเลอร์ทราบว่าคุณสมบัติจะเป็นประเภทที่คาดหวัง โดยปกติจะมี Extract ประเภทยูทิลิตี:

type MapToCleanOkayAgain<T extends [string, number][]> =
    { [K in keyof T]: Clean<Extract<T[K], [string, number]>> } // okay again

type CleanCoordinate2 = MapToCleanOkayAgain<MessyCoordinate>; // [number, number]

คุณสามารถใช้ Extract เพื่อแก้ไข MapToClean ต้นฉบับของคุณโดยไม่มีข้อจำกัด T:

type MapToCleanOkayUnconstrained<T> =
    { [K in keyof T]: Clean<Extract<T[K], [string, number]>> } // still okay

type CleanCoordinate3 = MapToCleanOkayUnconstrained<MessyCoordinate>; // [number, number]

แต่คุณอาจต้องการข้อจำกัดนั้น ไม่เช่นนั้นจะทำให้คุณส่งผ่านสิ่งแปลก ๆ ใน:

type BeCareful = MapToCleanOkayUnconstrained<{ a: 1, b: ["", 4], c: false }>;
/* type BeCareful = { a: never; b: 4; c: never; } */

มันขึ้นอยู่กับคุณ.


โอเค หวังว่าจะช่วยได้ ขอให้โชคดี!

ลิงก์ Playground ไปยังโค้ด

person jcalz    schedule 06.06.2020
comment
ขอบคุณ นี่คือสิ่งที่ฉันต้องการจริงๆ - person Matt Wynne; 07.06.2020
comment
ฉันมีคำถามติดตามผล แต่บางทีฉันควรถามแยกกัน ฉันประหลาดใจที่พบว่าค่าของประเภทที่แมปนี้ไม่สามารถวนซ้ำได้ (ต้องมีเมธอด '[Symbol.iterator]()' ที่ส่งคืนตัววนซ้ำ) มันใช้งานได้บน Playground แต่ไม่ใช่ในเครื่องของฉัน (ใช้งาน tsc 3.9.3) - person Matt Wynne; 07.06.2020

หากคุณรู้ล่วงหน้าว่าคุณจะแมป MessyCoordinate เพื่อรับ number แล้วทำไมคุณถึงทำให้งานของคุณซับซ้อน?

type MessyCoordinate = [
    [string, number],
    [string, number]
]
type MapToClean<T> = { [K in keyof T]: number }
type CleanCoordinate = MapToClean<MessyCoordinate>; // [number, number]
person Rachid Oussanaa    schedule 06.06.2020
comment
บางที MapToClean<[["",1],["",2],["",3]]> ควรให้ผลลัพธ์เป็น [1,2,3] ไม่ใช่ [number, number, number] - person jcalz; 06.06.2020
comment
@jcalz ขึ้นอยู่กับสิ่งที่ OP ต้องการ นั่นไม่ใช่สิ่งที่ฉันเข้าใจจากคำถามของเขา - person Rachid Oussanaa; 06.06.2020
comment
คำตอบของฉันตอบสนองต่อความต้องการเฉพาะของเขา ไม่ใช่คำตอบทั่วไปสำหรับปัญหาที่เขาหยิบยกขึ้นมา - person Rachid Oussanaa; 06.06.2020
comment
ฉันได้ทำให้ปัญหาง่ายขึ้นเพื่อพยายามทำให้ติดตามได้ง่ายขึ้น ขออภัย ฉันมีคำถามทั่วไปเกี่ยวกับความสามารถในการดึงไอเท็มออกจากทูเพิลด้านใน ในกรณีการใช้งานของฉัน ฉันจะไม่ทราบล่วงหน้าว่าประเภทเหล่านั้นคืออะไร และจะแตกต่างกันออกไป - person Matt Wynne; 06.06.2020