typescript - การกำหนดนามแฝงฟังก์ชันทั่วไปด้วยประเภทเฉพาะ
สมมติว่าฉันมีฟังก์ชันทั่วไป b ฉันอยากจะสามารถทำสิ่งต่อไปนี้ได้:
const a = b<X, Y, Z>;
ดังนั้น a(p, q, r) === b<X, Y, Z>(p, q, r).
ฉันจะทำให้สำเร็จได้อย่างไร?
วิธีหนึ่งที่ฉันรู้คือการทำอะไรบางอย่างเช่น const a=<X, Y, Z>(...props) => b<X, Y, Z>(...props) แต่จากนั้นฉันก็ต้องระบุประเภทของ props เป็น iterable เป็นต้น และฉันหวังว่าจะมีวิธีที่ดูเรียบร้อยกว่านี้
โดยเฉพาะอย่างยิ่ง ฉันกำลังมองหาที่จะทำสิ่งต่อไปนี้:
import { createAsyncThunk } from '@reduxjs/toolkit';
const createSpecificThunk = createAsyncThunk<ResponseType, PropsType>;
// Then, `... = createAsyncThunk<ResponseType, PropsType>(...)`
// should equal `... = createSpecificThunk(...)`
ฉันตระหนักว่าในกรณีของฉัน ฉันสามารถทำสิ่งต่อไปนี้ได้
const createSpecificThunk = (actionType: string, callback: (props: X) => Y) => (
createAsyncThunk<X, Y>(actionType, callback)
);
เพราะว่าประเภทแรกแทนค่าประเภทผลลัพธ์ และประเภทที่สองแทนค่าประเภทพร็อพส์! แต่ฉันยังสงสัยว่าข้างต้นสามารถทำได้กับเจนเนอริกหรือไม่
คำตอบ #1
ก่อน TypeScript 4.7 คุณสามารถระบุพารามิเตอร์ประเภทของฟังก์ชันทั่วไปได้ก็ต่อเมื่อคุณเรียกใช้ฟังก์ชันนั้นเท่านั้น:
declare function foo<T>(x: T): T[]; // generic function
let strArr = foo<string>("hello"); // specify T when calling
// const strArr: string[]
let numArr = foo<number>(123); // specify T when calling
// const numArr: number[]
และในขณะที่คอมไพเลอร์สามารถตรวจสอบได้ว่าฟังก์ชันเจเนอริกสามารถกำหนดค่าให้กับเวอร์ชันที่ไม่ใช่เจเนอริกได้เสมอเมื่อพารามิเตอร์ชนิดได้รับการระบุแล้ว:
let bar: (x: string) => string[] = foo; // okay
let baz: (x: number) => number[] = foo; // okay
คุณยังคงต้องทำสิ่งนี้ ด้วยตัวเอง ไม่มีวิธีใดที่จะบอกว่า "bar เหมือนกับ foo เมื่อคุณสร้าง T ด้วย string" ดังนั้นคุณจะต้องใช้วิธีฟังก์ชัน wrapper หรือวิธีแก้ปัญหาอื่น ๆ ที่ยุ่งยาก:
bar = (x: string) => foo(x); // wrapper, okay
แต่ TypeScript 4.7 จะนำเสนอ นิพจน์การสร้างอินสแตนซ์ ตามที่ได้ดำเนินการใน microsoft/TypeScript#47607, "ซึ่งให้ความสามารถในการระบุอาร์กิวเมนต์ประเภทสำหรับฟังก์ชันเจนเนอริกหรือคอนสตรัคเตอร์เจนเนอริกโดยไม่ต้องเรียกใช้งานจริง"
bar = foo<string>; // okay in TS4.7+
baz = foo<number>; // okay in TS4.7+
ดังนั้นเมื่อถึงเวลานั้น คุณจะสามารถเขียนโค้ดของคุณได้ตามที่ต้องการ:
const createSpecificThunk = createAsyncThunk<ResponseType, PropsType>; // okay TS4.7+
/* const createSpecificThunk: (
typePrefix: string,
payloadCreator: AsyncThunkPayloadCreator<ResponseType, PropsType, {}>,
options?: AsyncThunkOptions<PropsType, {}> | undefined
) => AsyncThunk<ResponseType, PropsType, {}> */
ลิงก์ Playground ไปยังโค้ด
