2

I found the following code byte in an open source repository recently:

interface Use<I, C = context<I>> { 
   <O>(fn: avvio.Plugin<O, I>, options?: O): C; 
} 

Simplified as:

interface F<A> {
  <B>(foo: A, bar: B): A;
}

How would I go about invoking the B generic?

I'm struggling to find an example usage of it and I can't make sense of it even in the TS Playground. I put this code in a playground you can view here.

1 Answer 1

3

It's an interface for a function that take's a generic parameter. Here is an example:

const funcTwo: F<string> = <T>(foo: string, bar: T) => {
  return `${foo} ${bar}`;
}

console.log(funcTwo('Hello', 7));

UPDATE: Adding a practical example that may show why it would be useful. It can be hard to come up with an example with no context but this is my best attempt without thinking too hard:

class UniqueCounter<T> {

  private underlyingSet = new Set<T>();

  constructor(
    private hashingFunc: <V>(value: V) => T,
  ) {

  }

  add<V>(thing: V) {
    const hash = this.hashingFunc(thing);
    this.underlyingSet.add(hash);
  }

  count() {
    return this.underlyingSet.size;
  }

}

This class attempts to count how many unique instances of something you have. However, the default set uses === for objects and that isn't what I want. Instead I have some kind of hashing algorithm for my particular objects. Although, in some cases I hash into a string and in other cases I hash into a number (the thing I hash into is T).

I can't add V to the class generics because then it would only be able to count one type of object. Maybe I can hash Person and Employee and Equipment and Room by using some kind of unique ID I've assigned to all those classes.

I can't add T to the hash function's type arguments because I need to use T to define underlyingSet.

UPDATE2:

Ignore the previous update as it isn't relevant to the question at hand. The type you showed:

interface F<A> {
  <B>(foo: A, bar: B): A;
}

is not equivalent to:

interface F<A, B> {
  (foo: A, bar: B): A;
}

Let's pretend we had a hashing factory factory that could magically create hashing objects, but they could only hash into one type of key. In other words, you could create a "hash anything to string" object or a "hash anything to number" object. We could define the class as:

class HashingFactory<T> {

  createHasher<V>(): Hasher;

}

However, what would the return type be? How would we define Hasher? If we define it as:

interface Hasher<K, V> {
  hash(value: V): K;
}

Then we are creating something that can only hash inputs of one type (e.g. it can only hash Employee into number). But our magical hasher can hash any object into a number. The proper interface would be:

interface Hasher<K> {
  <V>hash(value: V): K;
}

Now we can properly represent an object that can turn Employee or Room or Person (or anything else) into a number.

Sign up to request clarification or add additional context in comments.

8 Comments

I'm still struggling to see why this would be useful. Would it not be better to put it in the first line alongside the 'A' generic?
Added an example that may help clarify
Actually, nevermind, looking further at the question my example is not helpful at all and addresses something different.
So technically the interface could have other properties. Functions in JS can have properties and other methods attached to them just like objects. So the function could be callable and B may only apply to the function. However, the function could also have other properties & functions that refer to A. I can't think of any real world example.
Ok, added one more example which is hopefully clearer.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.