Patrick
Patrick

Reputation: 43

Flow Generic Function to create Generic Type

Let's say I have this generic flow type:

/* @flow */

type Cat<T> = {
  get:()=>T
};

And I want to create a function that creates a cat:

const makeCat:<U>(getter:()=>U)=>Cat<U> 
             = (getter) => ({get:getter});

Flow gives me the following error:

Cannot assign function to `makeCat` because `U` [1] is incompatible with `U` [2] in the return value of property `get` of the return value.

I've tried several different ways to define the types of the passed in 'getter', but it's always the same error.

Upvotes: 1

Views: 337

Answers (2)

Based on the answer by @kindaro, but simplified to not having to define the intermediary function type, by simply using the regular "old-school" function declaration form:

type Cat<T> = { get: () => T };

function makeCat<U>(getter: () => U): Cat<U> {
  return { get: getter };
}

// inferred as Cat<string>
const cat: Cat<string> = makeCat(() => 'secret');
// const cat: Cat<number> = makeCat(() => 'secret');  // Yields error

// inferred as string
const value: string = cat.get();
// const value: number = cat.get();  // Yields error

Flow Try link here

Upvotes: 0

kingdaro
kingdaro

Reputation: 12008

Try this. I broke up the logic of it in to a few extra steps to make it more understandable. The key part of this solution is using * to tell flow to "fill in the blanks" whenever the makeCat function is being used.

type Cat<T> = {
  get: () => T
}

// define signature of "makeCat" function
type MakeCat<U> = (getter: () => U) => Cat<U>

// use * to infer the variable at usage
const makeCat: MakeCat<*> = getter => ({ get: getter })

// inferred as Cat<string>
const cat = makeCat(() => 'secret')

// inferred as string
const value = cat.get()

Upvotes: 2

Related Questions