Skip to content

Allow type-level extraction of a class name as a string literal #43325

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
poteat opened this issue Mar 20, 2021 · 4 comments
Closed

Allow type-level extraction of a class name as a string literal #43325

poteat opened this issue Mar 20, 2021 · 4 comments

Comments

@poteat
Copy link

poteat commented Mar 20, 2021

Bug Report

Because class names cannot be modified and are known at compile time, they should be more narrowly typed.

🔎 Search Terms

  • class
  • name
  • constructor
  • string
  • literal
  • typeof
  • infer
  • narrow

🕗 Version & Regression Information

This behavior exists on Nightly (i.e. 4.3.0-dev.20210316) and the current version (4.2.3). It exists as far back as the compiler does - I was thereby not sure whether to classify this as a "bug" or a "feature request".

⏯ Playground Link

Playground link with relevant code

💻 Code

class Foobar {}

// @ts-ignore-error This emits an error as class names are readonly (as expected)
Foobar.name = "I can't name names"

// FooName is of type string rather than expected "Foobar"
type FooName = (typeof Foobar)["name"]

🙁 Actual behavior

FooName is of type string

🙂 Expected behavior

I would expect FooName to be inferred as type "Foobar", since the name cannot change (as per its readonly status).

A simple use-case would be a string-to-constructor record, but my use-case is actually generating sort of custom compiler error messages using string template literals. Right now I'm using the workaround of having a name attribute on each class, but it would be nice to not require that for my end-users.

@jcalz
Copy link
Contributor

jcalz commented Mar 21, 2021

I doubt they will think this is a bug; the name property of a function/class constructor is indeed of type string. You might want to consider filling out the feature request template instead of the bug report template.

Is this a dupe of #1579 maybe?

@poteat
Copy link
Author

poteat commented Mar 21, 2021

Oh, that would be a much stronger feature, assuming nameof in a type context would return a literal string type. I do think though that generally that types associated with class names should be inferred narrowly, for the same reason that:

const foo = "foobar";

foo // Type is "foobar" because `foo` was defined to be const.

@jcalz
Copy link
Contributor

jcalz commented Mar 21, 2021

#4628 and #3841 highlight some of the issues surrounding the static side of classes. With the notable exception of the construct signature itself, the static side of a class is inherited by subclasses, and thus forms a type hierachy:

class Foo {
  static someStaticProp = "Foo";
  a = 1;
}

class Bar extends Foo {
  b = 2;
}

Bar.someStaticProp; // exists

let fooCtor: typeof Foo = Bar; // okay

class Baz extends Foo {
  // construct signature incompatible with Foo
  constructor(public c: number) {
    super()
  };
}
fooCtor = Baz; // error

If the name property of a class constructor (or function) were to be strongly typed in the way you're asking for, then subclass constructors would never be assignable to superclass constructors (so let fooCtor: typeof Foo = Bar would be an error) and this would undoubtedly break quite a bit of real world code (this is one reason why I'm suggesting that you fill out the feature request template, as it asks you to consider such things).

At least the nameof feature wouldn't necessarily require subclass constructor compatibility to break.

@poteat
Copy link
Author

poteat commented Mar 21, 2021

Thanks @jcalz - I did not consider that.

I'm closing this out in lieu of #1579, as the current proposal above is unworkable (breaking changes is not my vision)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants