Coquelicot Coquelicot - 1 year ago 105
TypeScript Question

Creating a version of a generic function with the type 'clamped'

Let's say I have a function that returns some type parameterized by a generic. I'm going to be using this function a lot. Most of the time I'll be using one particular type - say

. For convenience, it would be nice to have an alias of this function just for numbers.

Toy example:

function arrayMaker<T>() : Array<T> {
return new Array<T>();
let numericalArrayMaker: () => Array<number> = arrayMaker<number>;

But the TypeScript compiler complains about the last line, thinking that I'm assigning type
to numericalArrayMaker.

I'm confused about why this fails, because I can assign a function (without a generic type) to a variable:

function foo() { return 0; }
let foo2 = foo;

... and I can assign a type (with a generic) to a variable:

type numericalArray = myArray<number>;

Is there a different syntax for what I'm trying to do?

(I understand that I could make my example work using a factory function returning "arrayMakers", but that becomes a good deal more verbose, and leads to some code duplication if my function takes arguments.)

Answer Source

All you need to do is save a reference of arrayMaker to another variable with the type you want:

function arrayMaker<T>() : Array<T> {
    return new Array<T>();

let numericalArrayMaker: () => Array<number> = arrayMaker
let mynums: number[] = numericalArrayMaker();

You can not use the generics with the function signature if you're not calling it, like: arrayMaker<number>, it makes no real sense.


I'm not sure why the compiler doesn't complain about

let numericalArrayMaker: (string) => number[] = arrayMaker;

It might be a bug, or maybe there's a better explanation which eludes me, if you do open an issue please post the url as a comment as I'd like to flow on that.

You can go around this issue though like this:

type ArrayMaker<T> = (value: T) => T[];

let numericalArrayMaker: ArrayMaker<number> = arrayMaker;
let mynums: number[] = numericalArrayMaker("foo"); // error

As for why this:

let a = arrayMaker<number>;

doesn't make sense, is that you are assigning a reference to the arrayMaker function into variable a, but there's no such thing as generics in js so there's no meaning to arrayMaker<number>.
What you want is casting:

let a = arrayMaker as arrayMaker<number>;

Maybe it will be clearer with classes:

class A<T> {}

let a1 = A<number>; // error
let a2 = A as A<number>; / ok

This works with:

type numericalArray = myArray<number>;

Because here you're dealing with the type of myArray and not the actual function.

This brings up something else that I personally believe in:
Don't write code in typescript for typescript, that is if the compiled code you wrote doesn't do anything, it was just written to get your ts compiling, then it's probably a bad idea.

I think that it's best to just go with:

let mynums: number[] = arrayMaker(4);
Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download