I would like to use a generic type as the parameter in the inner function of a higher order function. However, when I do this, the parameter(s) on the outer function lose their types (become any
).
Here's an example of what I'm trying to do. I expect to get an error on line 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)
When innerArg
is not generic, I get the error I expect:
type TestFunc = (outerArg: string) => (innerArg: boolean) => number
const test: TestFunc = (outerArg) => (innerArg: boolean) => innerArg ? outerArg * 3 : 0 // error because `outerArg` is `string` (expected)
On line 2 in the first example, outerArg
has type any
. On line 2 in the second example, outerArg
has type string
. Why are they different?
My goal is to allow T
to be specified when evaluating the outer function. For example:
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))
Here it is on typescript playground.
You have two functions:
1) A function with a generic type that returns a number,
2) and a function that takes a number and returns a generic.
As you mentioned in the comments, you're using an arrow function with a type parameter, but that won't work for both functions. You can declare your inner function as a generic, and your outer function with a type parameter:
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
It appears that this might be a bug in the compiler or by design.
But this might work as a work around for now where you attach the generic type to the function that uses the generic type.
type TestFunc = (outerArg: string) => <T>(innerArg: T) => number
OK, this is the way you would want to approach it to do what you want:
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")
Above will give you the error if you place arg1
like you did before and it will get you the generic form you wanted before. You will notice if you define the "sub type" incorrectly it will also give a compilation error.
For completeness here is a simpler solution (pretty much what cdbajorin did in his solution):
type TestFunc1 = <T>(arg1: string) => (a: T) => number
const test1: TestFunc1 = (arg1: string) => a => a ? (arg1 ? 1 : 2) : 0
const newNum2 = test1<number>("bluh")
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With