When it comes to TypeScript, there is no direct connection between string literal types (such as "IMyType") and the names of named types (like IMyType). String literal types represent actual string values present at runtime, while type names reflect elements of the static type system which are erased from the emitted JavaScript.
Moreover, TypeScript's type system is structural rather than nominal, meaning that the actual names of types hold less significance. For instance, declaring
type IYourType = IMyType;
simply assigns two different names to the same type - effectively making them interchangeable. As a result, successful completion of
SomeAbsClass.getSomething<IYourType>("IYourType");
implies that
SomeAbsClass.getSomething<IMyType>("IYourType");
should also succeed.
In essence, there isn't a defined way for the type system to prioritize one name over another; thus, ensuring that
SomeAbsClass.getSomething<IMyType>("IMyType");
succeeds while
SomeAbsClass.getSomething<IMyType>("IYourType");
fails automatically is not straightforward.
Since this automatic distinction does not occur, a possible solution involves manually creating a mapping interface linking string literals to their corresponding types:
interface TypeMapping {
IMyType: IMyType;
Date: Date;
string: string;
boolean: boolean;
// additional mappings
}
This mapping can then be utilized in defining getSomething()
, as shown below:
declare const SomeAbsClass: {
getSomething<T>(x: {
[K in keyof TypeMapping]: TypeMapping[K] extends T ? K : never }[keyof TypeMapping]
): void;
}
To call this method correctly, specify the generic type parameter explicitly:
SomeAbsClass.getSomething<IMyType>("IMyType"); // valid
SomeAbsClass.getSomething<IMyType>("IYourType"); // error
While functional, whether this approach aligns with your specific requirements remains uncertain.
Hopefully, this explanation proves beneficial. Best of luck!
Check out the code on TypeScript Playground