Neal
Neal

Reputation: 109

Typescript Generic Constraint where the property of one type depends on the other

I'm attempting to create a function that in use will look like this:

Foo(Number, (aNum: number) => {});

I am attempting to make this generic where the parameter of the callback in the second argument must be of the same type as the first.

The type in the first was easy:

function getObjectConstructor() {
  return Object.prototype.constructor;
}

type Type = ReturnType<typeof getObjectConstructor>

function thing(a: Type): void {
  console.log(a.name);
}

thing(Number);

However I am a little stuck on creating this dependency, basically I'm trying to read the name property value from Type and get the name from the second type and see if they match. Something like this:

interface HasName {
  name: string;
}

interface HasConstructor {
  constructor: HasName
}

function AreSameName<T extends Type, U extends HasConstructor>(a: T, b: U) {
  return a.name === b.constructor.name
}

But as a generic constraint. I'm not sure if this is possible, I'm new to Typescript.

Upvotes: 1

Views: 1506

Answers (1)

Joey Watts
Joey Watts

Reputation: 306

The name property of a function is typed as a string, so you don't have a string literal at compile time. You won't be able to cause compile errors based on the value of name.

As a possible alternative, you may be able to constraint the type of the second parameter to the InstanceType of the first parameter. (InstanceType<T> is the type you get when using the new operator on T.) See this example:

declare function test<T extends new (...args: any[]) => any>(
    ctor: T, value: InstanceType<T>
): any;

test(Number, 123);
test(Number, "123"); // Error: string is not assignable to number.
test(String, 123); // Error: number is not assignable to string.
test(String, "123");

// Object function returns "any", so anything goes...
test(Object, 123);

class A {
  private x: string = "hello";
}

class B {
  private y: number = 123;
}

test(A, "123"); // Error: string is not assignable to A.
test(B, new A()); // Error: A is not assignable to B.
test(B, new B());

Upvotes: 1

Related Questions