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

ไทป์สคริปต์ไทพ์ปิงส์สำหรับฟังก์ชันเคอร์รีแบบทั่วไป


ฉันพยายามที่จะเก่งขึ้นเกี่ยวกับ 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 ดังนั้นฉันจึงเขียนวิธีแก้ปัญหาเป็นการประกาศฟังก์ชันแทนการแสดงออกของฟังก์ชัน

บทความที่เกี่ยวข้อง