dsherret / ts-nameof

nameof in TypeScript
MIT License
492 stars 23 forks source link

Recommend: Don't use this package #121

Open dsherret opened 2 years ago

dsherret commented 2 years ago

I now recommend not using this package or any other compiler transforms. It's neat, but it creates code that is not portable and makes it hard to switch to new build systems. The current solutions for injecting compiler transforms are hacky and I can't imagine the TS compiler ever supporting this out of the box.

I personally now just use the following function. It's simple and it works for most cases... of course it's not as featureful, but it gets you 90% of the way there.

export function nameof<TObject>(obj: TObject, key: keyof TObject): string;
export function nameof<TObject>(key: keyof TObject): string;
export function nameof(key1: any, key2?: any): any {
  return key2 ?? key1;
}

Example Use

import { nameof } from "./some-relative-import";

interface SomeInterface {
  someProperty: number;
}

// with types
console.log(nameof<SomeInterface>("someProperty")); // "someProperty"

// with values
const myVar: SomeInterface = { someProperty: 5 };
console.log(nameof(myVar, "someProperty")); // "someProperty"
dobromyslov commented 2 years ago

Thank you for your candor. It would be awesome if you also write a note to this answer https://stackoverflow.com/a/33556815/1177597 when you have spare time.

PKnight-CheckWriters commented 2 years ago

Can you show how it should be used?

dsherret commented 2 years ago

@PKnight-CheckWriters I updated the main post to show some examples.

sotnikov-link commented 2 years ago

I published package ts-keyof. Maybe it will be useful for someone. Thanks for ts-nameof! I used it about 3 years, but now I need use esbuild and swc.

wh1t3cAt1k commented 2 years ago

@dsherret I'm on the fence about your recommendation... When one uses the keyof approach it's not automatically caught by VSCode refactoring tracking mechanism, and you get tons of compilation errors when renaming the keys.

If this issue was addressed by the VSCode team, I would probably try and make the switch.

PinkChampagne17 commented 2 years ago

@wh1t3cAt1k I published package ts-nameof-proxy, referenced properties can be renamed by VS Code and you can try to use it.

sotnikov-link commented 2 years ago

@wh1t3cAt1k If for you enough ts-keyof then you can disable useAliasesForRenames in VSCode: https://github.com/microsoft/TypeScript/issues/29238#issuecomment-494866713

Screen-Recording-2022-07-28-at-09 02 48

I declined rename for interface property in my lib, because it doesn't work with TypeScript Refactoring correctly: https://github.com/sotnikov-link/ts-keyof/issues/1

wh1t3cAt1k commented 2 years ago

@dsherret @sotnikov-link

If I am understanding it right, there is still one important consideration that still makes this library not deserving of deprecation.

When using ts-nameof, import type is often enough, which disappears completely at compile time, has no import side effects.

With runtime-based libraries, you need to actually import the whole dependency tree of the entity to "nameof", potentially introducing a build/runtime slowdown and even introducing circular dependencies.

I'm not completely persuaded that having no pre-processing steps is a big win. To me, it was never a hassle to set up a simple babel macro.

If there is a goal to transfer to swc, it might expose some extensibility too?

benjamin-rood commented 2 years ago

@dsherret Thanks for being transparent about the state of this package, it's much appreciated. Can you show me how I would go about implementing nameof.full, though? I see the full function defined in the exported namespace(s), but I don't see any function implementation in any typescript files... :thinking:

thexpand commented 1 year ago

There's still no way to get the name of the interface itself as a string, though.

celluj34 commented 1 year ago

How can I use this simplified method for variables without a parent object?

Something like

export function get_some_info(
  date: string | number,
  ...etc
) {
  if (!date) {
    console.log(`${nameof(date)} is required!`);
    return;
  }

  // ...etc
}
manuth commented 1 year ago

@dsherret Thanks for being transparent about the state of this package, it's much appreciated. Can you show me how I would go about implementing nameof.full, though? I see the full function defined in the exported namespace(s), but I don't see any function implementation in any typescript files... thinking

I know this is quite a late answer but just for clarification: You not finding a definition of nameof.full is because nameof.full doesn't run any code.

ts-nameof hooks into your compiler program (ttypescript, ts-patch or babel for example), finds all function calls to functions called nameof, nameof.full, nameof.split etc. and replaces them with the desired result.

So there is no drop-in replacement of ts-nameof. All we can do is wait and hope for typescript to implement it at some point.

manuth commented 1 year ago

How can I use this simplified method for variables without a parent object?

@celluj34 I think the package written by @sotnikov-link will help you. You'd have to change your code to something like this:

import { keyof } from "ts-keyof";

export function get_some_info(
  date: string | number,
  ...etc
) {
  if (!date) {
    console.log(`${keyof({ date })} is required!`);
    return;
  }

  // ...etc
longlostbro commented 1 year ago

I now recommend not using this package or any other compiler transforms. It's neat, but it creates code that is not portable and makes it hard to switch to new build systems. The current solutions for injecting compiler transforms are hacky and I can't imagine the TS compiler ever supporting this out of the box.

I personally now just use the following function. It's simple and it works for most cases... of course it's not as featureful, but it gets you 90% of the way there.

export function nameof<TObject>(obj: TObject, key: keyof TObject): string;
export function nameof<TObject>(key: keyof TObject): string;
export function nameof(key1: any, key2?: any): any {
  return key2 ?? key1;
}

Example Use

import { nameof } from "./some-relative-import";

interface SomeInterface {
  someProperty: number;
}

// with types
console.log(nameof<SomeInterface>("someProperty")); // "someProperty"

// with values
const myVar: SomeInterface = { someProperty: 5 };
console.log(nameof(myVar, "someProperty")); // "someProperty"

Could we get some more explanation on why this is no longer recommended? It seems to me, if your environment is controllable, then the pros outway the cons.

manuth commented 1 year ago

Hello everyone I know it's been a lot of time but I just wanted to note that only recently I indeed did publish a drop-in replacement for ts-nameof.

All you have to do is remove the @types/ts-nameof and ts-nameof packages and instead install my new "TypeScript nameof" project as described in the project's README.

Feel free to check it out: https://github.com/typescript-nameof/nameof

ShuuyaMonzen commented 1 month ago

improved simple solution

export function nameof<TObject>(obj: TObject, key: keyof TObject): string;
export function nameof<TObject>(key: keyof TObject): string;
export function nameof<TObject>(type: { new(...args: any[]): TObject }): string;
export function nameof(key1: any, key2?: any): any {
  if(typeof(key1) == 'function' && key1.name){
    return key1.name;
  }
  return key2 ?? key1;
}

add example

class User {}
nameof(User) → 'User'