6

In TypeScript 4.1, is it possible to get a class name or a function name as literal string type?

e.g.

class Foo { }

type Tpl = `${Foo["name"]}_${"a" | "b" | "c"}`; // error
// should be
// "Foo_a" | "Foo_b" | "Foo_c"

Edit (extended use cases)

Since the first example is not enough explicit and could be resolved with "Foo_a" | "Foo_b" | "Foo_c" as type, here another ones.


class Animal { /* code */ }
class Dog extends Animal { }
class Cat extends Animal { }
class Duck extends Animal { }
// also, someone outside my original code decide to implement another
// animal, and so on. (for example, "MyAwesomeChimera")
class MyAwesomeChimera extends Animal { }

// "try" to extract name
type GetName<T extends Function> = T["name"]; // return string for now
// the goal here is, for whatever reasons,
// to use template literal to pre validate a query string
// that uses class names
type ClassQueryTemplate<T extends Array<typeof Animal>> =
  `CQT ${ GetName<T[number]> }---CALL()`;

function querier<T extends Array<typeof Animal>>(...animals: T):
  (query: ClassQueryTemplate<T>) => void { /* code */ return null as any; }

// impl & usage
const query = querier(
  Dog,
  Duck,
  MyAwesomeChimera,
  Cat,
);

// tests
query(`CQT Duck---CALL()`); // ok, but no autocomplete
query(`CQT Dog---CALL()`); // ok, but no autocomplete
query(`CQT Cat---CALL()`); // ok, but no autocomplete
query(`CQT MyAwesomeChimera---CALL()`); // ok, but no autocomplete
query(`CQT Horse---CALL()`); // ok but should be error
// basically, the query string is typed as: `CQT ${string}---CALL()`
// which is not good

Playground Link

I saw the "nameof" operator proposal and I hope that is not the "answer".

lsagetlethias
  • 328
  • 2
  • 14
  • Why... why would you try and do it like that? Type must be strictly known as literal values when you're writing the code. Trying to compute them with literals wouldn't work, nor would it be useful. Why not just write `type Tpl = "Foo_a" | "Foo_c" | "Foo_b"`? You're not really saving any time or effort by doing it elsewise. – jered Sep 26 '20 at 03:30
  • @jered I added a more concrete example – lsagetlethias Sep 26 '20 at 10:00
  • This is possible in the 4.1 beta: https://devblogs.microsoft.com/typescript/announcing-typescript-4-1-beta/ – ccarton Sep 26 '20 at 11:27
  • @ccarton Well .. Template literal types, yeah, I know, that's why I started my question with "In TypeScript 4.1 ..." ; sadly, nowhere on Daniel's post I could find something about class names as literal types. – lsagetlethias Sep 26 '20 at 11:31
  • I don't think this is possible, because `Function.name` variable is of type string, TypeScript doesn't make this function of string literal type for every particular function or class. Solution with template string will certainly not work, because they exist only in TS 4.1. The only option I see is to make `Animal` class abstract and declare an abstract field `name`, but still it will be of type `string`, not of constant type. I'm pretty sure it's impossible to do this, maybe you will have to rethink your solution a bit or live without autocompletion – Alex Chashin Sep 26 '20 at 13:46

0 Answers0