ไทป์สคริปต์ไทพ์ปิงส์สำหรับฟังก์ชันเคอร์รีแบบทั่วไป
ฉันพยายามที่จะเก่งขึ้นเกี่ยวกับ FP แต่กำลังประสบปัญหาเกี่ยวกับการจัดการการพิมพ์ฟังก์ชัน 'curry' แบบทั่วไป
ตัวอย่างเช่น ฉันได้เขียนเวอร์ชัน "Curry" ของ reduce:
const reduce = <S, R>(fn: (result: R, obj: S, i?: number, arr?: S[]) => R, init: R) =>
(objects: S[]) =>
objects.reduce(fn, init);
const numToSum: number[] = [1,2,3,5,8,13];
const result = reduce((sum, n) => sum + n, 0)(numToSum);
ปัญหาคือ typescript ไม่สามารถทราบชนิดของ S ได้จนกว่าคุณจะเรียกฟังก์ชัน curry ด้วย numToSum จริง ๆ
มันชัดเจนมากขึ้นเมื่อคุณเห็นมันโดยไม่มีการเรียกแกง:
const sumNumbersFn = reduce((sum, n) => sum + n, 0);
ในกรณีนี้คุณสามารถแก้ไขได้โดยการพิมพ์อาร์กิวเมนต์ของฟังก์ชันเองด้วย n: number หรือการตั้งค่าพารามิเตอร์ทั่วไปอย่างชัดเจน <number[], number>
ข้อแรกดูสมเหตุสมผล แต่สิ่งที่ฉันเจอคือเมื่อสิ่งต่าง ๆ ซับซ้อนมากขึ้น ฉันต้องคอยให้ลายเซ็นทั่วไปอยู่ตลอดเวลา
ฉันสงสัยว่าฉันพลาดอะไรไปหรือเปล่า และจริง ๆ แล้วมันเป็นไปได้ไหมที่ TypeScript จะสามารถ "อนุมาน" ประเภทจากการเรียกฟังก์ชันในภายหลังได้?
กลับไปที่ตัวอย่างแรก:
const result = reduce((sum, n) => sum + n, 0)(numToSum);
ดูเหมือนว่าคอมไพเลอร์จริงๆ ควรมีข้อมูลทั้งหมดที่จำเป็นในการอนุมานประเภท
อัปเดต
นี่คือตัวอย่างที่ชัดเจน/เต็มรูปแบบมากขึ้นของปัญหาที่ฉันกำลังเจอ
สนามเด็กเล่น TS
คำตอบ #1
สิ่งที่คุณต้องทำมีเพียงประกาศฟังก์ชันซึ่งคุณส่งกลับจากฟังก์ชัน select เป็นแบบทั่วไป:
function select<T, S>(sFn: (obj: T) => S) {
function computation<G>(fn: (obj: S) => G) {
return (obj: T) => fn(sFn(obj));
}
return computation;
}
ป.ล.: ฉันไม่รู้ว่าทำไมไวยากรณ์แบบนี้ถึงใช้ไม่ได้ใน TS playground:
const select = <T, S>(sFn: (obj: T) => S) => <G>(fn: (obj: S) => G) => {
return (obj: T) => fn(sFn(obj));
}
อาจเป็นเพราะการตั้งค่าบางอย่างของ TS ดังนั้นฉันจึงเขียนวิธีแก้ปัญหาเป็นการประกาศฟังก์ชันแทนการแสดงออกของฟังก์ชัน
