ประเภท Typescript ที่มีคุณสมบัติเฉพาะไม่เกิน 10 รายการ หรือทูเพิลแบบรายการที่มีความยาว 0 - 10
ฉันกำลังเขียนโค้ดห่อหุ้มทั่วไปบางส่วนเหนือ SDK ของ AWS ใน Javascript SDK นั้นแย่มากในบางแง่มุมที่ฉันอยากทำให้มันเจ็บปวดน้อยลงเล็กน้อย
SQS อนุญาตให้ส่งผ่านแอตทริบิวต์ของข้อความบางส่วน (MessageBodyAttributeMap) สำหรับวัตถุประสงค์ของคำถามนี้ เราจะสมมติว่ามีการพิมพ์เป็น { [key: string]: Buffer | Uint8Array | Blob | string } (นี่เป็นส่วนหนึ่งของความสะดวกสบายที่ฉันหวังว่าจะเพิ่ม)
แต่ ข้อจำกัดที่ไม่ได้ระบุไว้ที่นี่คือว่าในวัตถุแอตทริบิวต์ข้อความนี้สามารถมีได้เพียง 10 คุณสมบัติ และดูเหมือนจะเป็นไปไม่ได้ที่จะบังคับจำนวนคุณสมบัติของวัตถุที่เฉพาะเจาะจงใน TypeScript อย่างไรก็ตามมีสิ่งที่สามารถบังคับความยาวได้ คือ ทูเพิลของรายการที่ฉันสามารถแปลงเป็นวัตถุได้อย่างง่ายดายในเวลารันไทม์:
type MessageValue = Buffer | Uint8Array | Blob | string
type Entry<
TKey extends string,
TValue extends MessageValue
> = TKey extends never
? never
: TValue extends never
? never
: [TKey, TValue]
type EntryTuple<
TEntry1 extends Entry<string, MessageValue> = never
TEntry2 extends Entry<string, MessageValue> = never
// T3 - T9
TEntry10 extends Entry<string, MessageValue> = never
> = [TEntry1, TEntry2, /* T3 - T9 */, TEntry10]
ในทางทฤษฎี คลาสคอนกรีต DurableQueue ที่รับอาร์กิวเมนต์ชนิดทั่วไป TEntry1 - TEntry10 สามารถล็อกชุดของเอนทรีเฉพาะในเวลาสร้างเพื่อให้ระบบชนิดบังคับใช้ชนิด AttributeMap ทั้งในข้อความขาเข้าและขาออกได้ ผมยินดีที่จะรับอ็อบเจกต์ แต่ก็อยากได้ชุดเอนทรีที่เหมาะสมสำหรับ Object.fromEntries() และสามารถส่งคืนเอนทรีด้วยการใช้ Object.toEntries() ด้วย
แต่ว่ามีปัญหาร้ายแรงบางอย่าง
- ประเภทสามารถเป็นยูเนียนได้เสมอ ในฐานะทูเพิล ไม่มีการรับประกันว่าคีย์แต่ละรายการจะเป็นสตริงคงที่เพียงตัวเดียว
- ตอนนี้ฉันก็พยายามหาวิธีที่จะให้ค่าแต่ละค่ามีชนิดเฉพาะเจาะจงเพื่อที่มันจะได้ไม่แตกต่างกันในแต่ละรายการของทูเพิล
Object.toEntries()ไม่มีการรับประกันเกี่ยวกับลำดับของคีย์ บางทีฉันอาจจะแก้ปัญหานี้ได้โดยให้คลาสของฉันรับ callback สำหรับการจัดเรียง entry และอนุญาตให้ผู้เรียกที่สร้างสามารถรับประกันได้ว่าตัวจัดเรียงจะตรงกับลำดับของประเภททูเพิลที่ส่งออก- ความโดดเด่นจะเป็นปัญหา ฉันอาจจะสามารถใช้ประเภทเรียกซ้ำอัจฉริยะบางอย่างเพื่อรวมคีย์ TEntry1 - TEntry10 ทั้งหมดเข้าด้วยกันและแน่ใจว่าปริมาณอินพุตตรงกับปริมาณคีย์ที่รวมกัน (และลบซ้ำ)
ฉันสามารถเลื่อนการกำหนดของ pseudo-MessageBodyAttributeMap ของฉันไปยังเวลาสร้างผ่านอาร์กิวเมนต์ชนิดทั่วไปได้อย่างไร?
เพื่อพยายามทำให้สิ่งนี้เป็นรูปธรรมมากขึ้น ถ้าฉันจะกำหนดประเภทแบบคงที่ให้กับคลาสของฉัน เพื่อให้เมธอดคลาส queue() ด้านล่างมีคำจำกัดความ AttributeMap ที่ชัดเจนหนึ่งข้อ (ซึ่งเมธอดนี้จะเรียก SQS.sendMessage()) มันอาจจะมีลักษณะดังนี้ โดยที่ TypeArguments แทนพารามิเตอร์ชนิดที่ไม่ทราบซึ่งฉันต้องใช้เพื่อให้บรรลุเป้าหมาย:
class SqsQueue<TypeParameters> implements IDurableQueue<TypeParameters> {
private readonly _sqs: SQS
constructor<TypeParameters>(sqs: SQS) {
this._sqs = sqs
}
async queue(
body: string,
attributeMap: [
['attribute1', Uint8Array],
['attribute2', string],
['attribute3', Buffer]
] // the concrete type of up to 10 entries
// or an equivalent object with no more than 10 properties
// that was actually specified by the new() call's type arguments
) {
const result = await this._sqs.sendMessage({
MessageAttributes: convertAttributeMapToSqsMessageAttributes(attributeMap),
...
})
...
return transformedResult
}
}
นั่นคือ เมื่อเราสร้างอินสแตนซ์ของคลาสข้างต้น:
const myQueue: IDurableQueue<...> =
new SqsDurableQueue<
[
['attribute1', Uint8Array],
['attribute2', string],
['attribute3', Buffer]
]
>()
อาร์กิวเมนต์ชนิดจะอยู่ในรูปแบบที่แสดง แต่ต้องถูกกำหนดโดยข้อจำกัดของพารามิเตอร์ชนิดของคลาสเพื่อ:
- เป็นทูเพิลที่มีความยาวระหว่าง 0 ถึง 10 รายการ
- ใช้คีย์การเข้ารหัสสตริงที่ไม่ซ้ำกัน
- และรับประกันว่าค่าของแต่ละรายการจะเป็นเพียงหนึ่งใน
Buffer | Uint8Array | Blob | string
ฉันรู้ว่านี่เป็นคำถามที่ซับซ้อนและอาจเป็นเรื่องยากที่จะถาม บางทีหลังจากนอนพักสักหน่อยมันอาจทำให้ฉันมีแรงบันดาลใจ (ซึ่งเป็นสิ่งที่มักเกิดขึ้นบางครั้ง) ในระหว่างนี้ฉันติดอยู่กับวิธีที่จะอนุญาตให้สร้างคลาส DurableQueue ได้อย่างเป็นรูปธรรม ซึ่งในทางปฏิบัติ (แม้ไม่ใช่ความจริงทั้งหมด) จะทำให้ฉันสามารถกำหนดวัตถุที่มีคุณสมบัติไม่เกิน 10 อย่างตามที่อธิบายไว้
คำถามของฉันดูเหมือนจะแย่มาก; ฉันแน่นอนว่ากำลังมีปัญหาในการอธิบายอย่างสั้นกระชับในสิ่งที่ฉันพยายามทำ ขอโทษสำหรับเรื่องนั้น และสำหรับผู้อ่านที่อ่านมาถึงตรงนี้ ฉันรู้สึกขอบคุณมาก!
ป.ล. ผมเพิ่งนึกถึงมิกซิน แต่จริง ๆ แล้วยังไม่เคยใช้มันสำเร็จเลย ผมแค่ลองเล่นบ้างเป็นครั้งคราว ไม่แน่ใจว่ามันจะช่วยแก้ปัญหาได้ยังไง ผมสงสัยว่าการใช้ 'วัตถุต้นแบบ' ในฟังก์ชันแฟกทอรี่มิกซิน (เพื่ออนุมานประเภท MessageAttributes) จะช่วยสร้างประเภทที่อย่างน้อย ตอนสร้างจะเกิดข้อผิดพลาดถ้าวัตถุต้นแบบมีมากกว่า 10 คุณสมบัติได้ไหม?