Function/ClassConstructor name issue

coolchaem·2022년 5월 23일
0

TypeScript

목록 보기
3/3

background

Function과 Class에는 read-only nme property가 존재한다.

Function.name

function.name 하면 함수 이름을 반환해준다.

function test() {}
console.log(test.name); // test

Class.constructor.name

객체로 생성된 object도 constructor.name을 사용할 수 있다.

class ClassTest {}
let a = new ClassTest();
console.log(a.constructor.name); // ClassTest

issue

webpack으로 난독화(uglify)와 압축(minify)되면서 name이 production mode에선 유지되지 않았다.
의미가 없는 e나 i출력되거나, 클래스도 여러개가 하나로 합쳐지면서 코드 사용이 어려워지는 현상이었고 관련 워닝이 mdn에 기록되어 있었다.

설명된 예시를 좀 더 해석해보면 이렇다.
아래 코드처럼 원래는 Foo로 함수를 생성하였다고 한다.

function Foo() {};
let foo = new Foo();

if (foo.constructor.name === 'Foo') {
  console.log("'foo' is an instance of 'Foo'");
} else {
  console.log('Oops!');
}

그러나 압축되면서 이런 방식으로 변경이 되면서 코드가 기존 로직으로 돌아가지 않는 것이다.

function a() {};
let b = new a();
if (b.constructor.name === 'Foo') {
  console.log("'foo' is an instance of 'Foo'");
} else {
  console.log('Oops!');
}

방안

  • webpack 설정 수정
    keep_fnames, keep_classnames를 유지하는 옵션이 있다.
    다만 이렇게 했을 때 압축과 난독화의 장점을 가지고 가지 못하니, 보안성과 파일 사이즈가 늘어날 것이다.

  • 선언 확장과 eslint
    global declare로 선언 확장해서 deprecated 표시를 해서 lint에 걸리게 한다는 글을 발견했다. typescript 라면 유용할 것으로 보인다.

declare global {
  interface Function {
    /** @deprecated Don't use this, think about the children!*/
    readonly name: string;
  }
}

"rules": {
  "deprecation": true
}

실제 적용

  • global.d.ts를 src/types 폴더 아래 생성하였다.
declare global {
  interface Function {
    /**
     * Returns the name of the function. Function names are read-only and can not be changed.
     * @deprecated no recommended our feature due to wepback minify/uglify features
     */
    readonly name: string;
  }
}

export {};
  • eslint-plugin-deprecation 설치

typescript랑만 사용 가능하다.

npm i -D eslint-plugin-deprecation

eslint 에 plugin을 추가하고 rule도 설정하였다. rule은 strict하게 error로 가져가려고 한다.

...
  plugins: ['@typescript-eslint', 'react-hooks', 'deprecation'],
...
  parserOptions: {
    ecmaVersion: 2020,
    sourceType: 'module',
    project: './tsconfig.json',
  },
...
  rules: {
...
      'deprecation/deprecation': 'error',

https://www.npmjs.com/package/eslint-plugin-deprecation

결과

임의로 추가한 deprecated 선언도 잘 출력되는 것을 보았다

reference

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/name
https://medium.com/@eransakal/fix-javascript-issues-with-function-name-7079742f1a05
https://stackoverflow.com/questions/64876188/typescript-prevent-use-of-name-to-get-function-class-name

profile
Front-end developer

0개의 댓글