This will take a bit to explain.
I have a class called Dependency, which holds a value of generic type T and provides some helper methods (not really relevant here):
class Dependency<T> {
value: T
...
}
I'm trying to write another class, Derivative, that takes a list of dependencies and a derive function to generate some other value:
type DependencyArray = Array<Dependency<any>>
type DeriveFunc<T, D extends DependencyArray = DependencyArray> = (...deps: D) => Promise<T>
class Derivative<T, D extends DependencyArray = DependencyArray> {
value: T
constructor(
dependencies: D,
derive: DeriveFunc<T, D>,
) { ... }
}
Here's the catch – I want to restrict derive to only accept dependencies provided by first argument to Derivative constructor.
For example:
const depA = new Dependency<string>()
const depB = new Dependency<boolean>()
// Good: this one compiles
const new Derivative<string>([depA, depB], async ([a, b]) => `${a}-${b}`)
// Good: these two fail to compile, since arrays aren't the same length
// TS2345: Source has 2 element(s) but target allows only 1.
const new Derivative<string>([depA, depB], async ([a]) => `${a}`)
const new Derivative<string>([depA], async ([a, b]) => `${a}`)
// Bad: in this one, `derive` function doesn't understand which types are in dependency array, so it merges it to Dependency<string | boolean>[]
// TS2339: Property 'length' does not exist on type 'boolean | string'.
// Property 'length' does not exist on type 'false'.
const new Derivative<string>([depA, depB], async ([a, b]) => `${a.length}-${b}`)
Is there a way to reference exactly the dependencies that were passed to Derivative constructor?