typescript - Kiểu tổng quát trong các hàm bậc cao
Tôi muốn sử dụng một kiểu tổng quát làm tham số trong hàm bên trong của một hàm bậc cao. Tuy nhiên, khi tôi làm điều này, các tham số của hàm bên ngoài sẽ mất kiểu của chúng (trở thành any ).
Đây là một ví dụ về điều tôi đang cố gắng làm. Tôi dự đoán sẽ nhận được lỗi ở dòng 2.
type TestFunc = <T>(outerArg: string) => (innerArg: T) => number
const test: TestFunc = <T>(outerArg) => (innerArg: T) => innerArg ? outerArg * 3 : 0 // no error because `outerArg` is `any` (unexpected)
Khi innerArg không phải là kiểu tổng quát, tôi nhận được lỗi như mong đợi:
type TestFunc = (outerArg: string) => (innerArg: boolean) => number
const test: TestFunc = (outerArg) => (innerArg: boolean) => innerArg ? outerArg * 3 : 0 // error because `outerArg` is `string` (expected)
Câu hỏi
Ở dòng 2 trong ví dụ đầu tiên, outerArg có kiểu any. Ở dòng 2 trong ví dụ thứ hai, outerArg có kiểu string. Tại sao chúng lại khác nhau?
Thêm chi tiết
Mục tiêu của tôi là cho phép T được chỉ định khi đánh giá hàm bên ngoài. Ví dụ:
type TestFunc = <T>(outerArg: string) => (innerArg: T) => number
const test: TestFunc = (outerArg) => (innerArg) => innerArg ? outerArg.length * 3 : 0
const test2: TestFunc = <T>(outerArg) => (innerArg: T) => innerArg ? outerArg * 3 : 0 // want error
const fourBool = test<boolean>('str')
console.log(fourBool(true))
console.log(fourBool(1)) // want error
const fourNum = test<number>('str')
console.log(fourNum(true)) // want error
console.log(fourNum(1))
Đây là nó trên playground của TypeScript.
Câu trả lời #1
Bạn có hai chức năng:
1) Một hàm với kiểu tổng quát mà trả về một số,
2) và một hàm nhận một số và trả về một kiểu tổng quát.
Như bạn đã đề cập trong phần bình luận, bạn đang sử dụng một hàm mũi tên với tham số kiểu, nhưng điều đó sẽ không hoạt động cho cả hai hàm. Bạn có thể khai báo hàm bên trong của mình như một hàm generic, và hàm bên ngoài của bạn với một tham số kiểu:
type InnerFunc<T> = (inner: T) => number;
type TestFunc = <T>(outer: number) => InnerFunc<T>;
const test: TestFunc = <T>(outerArg: number) => (innerArg: T) => innerArg ? outerArg * 3 : 0;
const fourBool = test<boolean>(4);
fourBool(true); // OK
fourBool(1); // error
Câu trả lời #2
Có vẻ như đây có thể là một lỗi trong trình biên dịch hoặc do thiết kế.
Nhưng điều này có thể hoạt động như một giải pháp tạm thời cho hiện tại, nơi bạn gắn kiểu tổng quát vào hàm sử dụng kiểu tổng quát đó.
type TestFunc = (outerArg: string) => <T>(innerArg: T) => number
Được rồi, đây là cách bạn sẽ muốn tiếp cận để làm những gì bạn muốn:
type TestFunc = (arg1: string) => <T>(a: T) => number
type Number1 = (a: number) => number
const test: TestFunc = (arg1) => (a) => a ? (arg1 ? 1 : 2) : 0
const num1: Number1 = test("blah")
// OR
const newNum1 = <Number1>test("bleh")
Phần trên sẽ cho bạn lỗi nếu bạn đặt arg1 như trước đây và nó sẽ đưa cho bạn dạng tổng quát mà bạn muốn trước đó. Bạn sẽ nhận thấy nếu bạn định nghĩa "loại con" không đúng, nó cũng sẽ gây lỗi biên dịch.
Để đầy đủ, đây là một giải pháp đơn giản hơn (gần như là những gì cdbajorin đã làm trong giải pháp của anh ấy):
type TestFunc1 = <T>(arg1: string) => (a: T) => number
const test1: TestFunc1 = (arg1: string) => a => a ? (arg1 ? 1 : 2) : 0
const newNum2 = test1<number>("bluh")
