Typescript: ๊ธฐ๋Šฅ์š”์ฒญ: ํด๋ž˜์Šค ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ ๋Œ์—ฐ๋ณ€์ด

์— ๋งŒ๋“  2015๋…„ 09์›” 20์ผ  ยท  231์ฝ”๋ฉ˜ํŠธ  ยท  ์ถœ์ฒ˜: microsoft/TypeScript

์ด๊ฒƒ์ด ํ˜•์‹ ๊ฒ€์‚ฌ๋ฅผ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ๋‹ค๋ฉด ์ƒ์šฉ๊ตฌ ์—†๋Š” ๋ฏน์Šค์ธ์„ ์™„๋ฒฝํ•˜๊ฒŒ ์ง€์›ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

declare function Blah<T>(target: T): T & {foo: number}

<strong i="6">@Blah</strong>
class Foo {
    bar() {
        return this.foo; // Property 'foo' does not exist on type 'Foo'
    }
}

new Foo().foo; // Property 'foo' does not exist on type 'Foo'
Needs Proposal Suggestion

๊ฐ€์žฅ ์œ ์šฉํ•œ ๋Œ“๊ธ€

๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋ฐฉ๋ฒ•์—๋„ ์œ ์šฉํ•ฉ๋‹ˆ๋‹ค.

class Foo {
  <strong i="6">@async</strong>
  bar(x: number) {
    return x || Promise.resolve(...);
  }
}

๋น„๋™๊ธฐ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋Š” ๋ฐ˜ํ™˜ ์œ ํ˜•์„ Promise<any> ๋กœ ๋ณ€๊ฒฝํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

๋ชจ๋“  231 ๋Œ“๊ธ€

๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋ฐฉ๋ฒ•์—๋„ ์œ ์šฉํ•ฉ๋‹ˆ๋‹ค.

class Foo {
  <strong i="6">@async</strong>
  bar(x: number) {
    return x || Promise.resolve(...);
  }
}

๋น„๋™๊ธฐ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋Š” ๋ฐ˜ํ™˜ ์œ ํ˜•์„ Promise<any> ๋กœ ๋ณ€๊ฒฝํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

@Gaelan , ์ด๊ฒƒ์ด ๋ฐ”๋กœ ์šฐ๋ฆฌ์—๊ฒŒ ํ•„์š”ํ•œ ๊ฒƒ์ž…๋‹ˆ๋‹ค! ๋ฏน์Šค์ธ์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์ž์—ฐ์Šค๋Ÿฝ์Šต๋‹ˆ๋‹ค.

class asPersistent {
  id: number;
  version: number;
  sync(): Promise<DriverResponse> { ... }
  ...
}

function PersistThrough<T>(driver: { new(): Driver }): (t: T) => T & asPersistent {
  return (target: T): T & asPersistent {
    Persistent.call(target.prototype, driver);
    return target;
  }
}

@PersistThrough(MyDBDriver)
Article extends TextNode {
  title: string;
}

var article = new Article();
article.title = 'blah';

article.sync() // Property 'sync' does not exist on type 'Article'

์ด๊ฒƒ์— ๋Œ€ํ•ด +1. ์ด๊ฒƒ์ด ๊ตฌํ˜„ํ•˜๊ธฐ ์–ด๋ ต๊ณ  ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ ๋Œ์—ฐ๋ณ€์ด ์˜๋ฏธ๋ก ์— ๋Œ€ํ•œ ํ•ฉ์˜์— ๋„๋‹ฌํ•˜๊ธฐ๊ฐ€ ๋” ์–ด๋ ต๋‹ค๋Š” ๊ฒƒ์„ ์•Œ๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

+1

์ด๊ฒƒ์˜ ์ฃผ์š” ์ด์ ์ด ์œ ํ˜• ์„œ๋ช…์— ์ถ”๊ฐ€ ๋ฉค๋ฒ„๋ฅผ ๋„์ž…ํ•˜๋Š” ๊ฒƒ์ด๋ผ๋ฉด ์ด๋ฏธ ์ธํ„ฐํŽ˜์ด์Šค ๋ณ‘ํ•ฉ์„ ํ†ตํ•ด ์ด๋ฅผ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

interface Foo { foo(): number }
class Foo {
    bar() {
        return this.foo();
    }
}

Foo.prototype.foo = function() { return 10; }

new Foo().foo();

๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๊ฐ€ ํด๋ž˜์Šค๋ฅผ ๋ช…๋ น์ ์œผ๋กœ ๋ณ€๊ฒฝํ•˜๊ธฐ ์œ„ํ•ด ์ปดํŒŒ์ผ๋Ÿฌ๊ฐ€ ํ˜ธ์ถœํ•ด์•ผ ํ•˜๋Š” ์‹ค์ œ ํ•จ์ˆ˜์ธ ๊ฒฝ์šฐ, ์ด๊ฒƒ์€ ํ˜•์‹ ์•ˆ์ „ ์–ธ์–ด์ธ IMHO์—์„œ ์ˆ˜ํ–‰ํ•˜๋Š” ๊ด€์šฉ์ ์ธ ์ž‘์—…์ฒ˜๋Ÿผ ๋ณด์ด์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

@masaeedu ๋ฐ์ฝ”๋ ˆ์ดํŒ…๋œ ํด๋ž˜์Šค์— ์ •์  ๋ฉค๋ฒ„๋ฅผ ์ถ”๊ฐ€ํ•˜๋Š” ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•์„ ์•Œ๊ณ  ์žˆ์Šต๋‹ˆ๊นŒ?

@davojan ๋ฌผ๋ก ์ž…๋‹ˆ๋‹ค. ์—ฌ๊ธฐ ์žˆ์Šต๋‹ˆ๋‹ค:

class A { }
namespace A {
    export let foo = function() { console.log("foo"); }
}
A.foo();

๋ฉ”์„œ๋“œ๋ฅผ ์žฅ์‹ํ•  ๋•Œ ํด๋ž˜์Šค์— _multiple_ ์†์„ฑ์„ ๋„์ž…ํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒƒ๋„ ์œ ์šฉํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค(์˜ˆ: getter์— ๋Œ€ํ•œ ๊ด€๋ จ setter๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๋„์šฐ๋ฏธ ๋˜๋Š” ์ด๋Ÿฌํ•œ ๋ผ์ธ์„ ๋”ฐ๋ผ ๋ฌด์–ธ๊ฐ€).

connect ์— ๋Œ€ํ•œ react-redux ํƒ€์ดํ•‘์€ ๊ตฌ์„ฑ ์š”์†Œ๋ฅผ ์ทจํ•˜๊ณ  redux๋ฅผ ํ†ตํ•ด ์ˆ˜์‹ ๋œ ์—ฐ๊ฒฐ๋œ props๋ฅผ ํฌํ•จํ•˜์ง€ ์•Š๋Š” props์˜ ์ˆ˜์ •๋œ ๊ตฌ์„ฑ ์š”์†Œ๋ฅผ ๋ฐ˜ํ™˜ํ•˜์ง€๋งŒ TS๋Š” connect ์ •์˜๋ฅผ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ธ์‹ํ•˜์ง€ ๋ชปํ•˜๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. ์ด ๋ฌธ์ œ๋กœ ์ธํ•ด ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ. ๋ˆ„๊ตฌ๋“ ์ง€ ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•์ด ์žˆ์Šต๋‹ˆ๊นŒ?

ClassDecorator ์œ ํ˜• ์ •์˜๊ฐ€ ๋ณ€๊ฒฝ๋˜์–ด์•ผ ํ•œ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

ํ˜„์žฌ declare type ClassDecorator = <TFunction extends Function>(target: TFunction) => TFunction | void; ์ž…๋‹ˆ๋‹ค. ๋กœ ๋ณ€๊ฒฝ๋  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

declare type MutatingClassDecorator = <TFunction extends Function>(target: TFunction) => TFunction | void;
declare type WrappingClassDecorator = <TFunction extends Function, TDecoratorFunction extends Function>(target: TFunction) => TDecoratorFunction;
declare type ClassDecorator = MutatingClassDecorator | WrappingClassDecorator;

๋ถ„๋ช…ํžˆ ๋„ค์ด๋ฐ์€ ํ˜•ํŽธ์—†๊ณ  ์ด๋Ÿฐ ์ข…๋ฅ˜์˜ ์ผ์ด ์ž‘๋™ํ•˜๋Š”์ง€ ์ „ํ˜€ ๋ชจ๋ฆ…๋‹ˆ๋‹ค(์ €๋Š” ๊ทธ๋ƒฅ Babel ์•ฑ์„ ํƒ€์ดํ”„์Šคํฌ๋ฆฝํŠธ๋กœ ๋ณ€ํ™˜ํ•˜๋ ค๊ณ  ํ•˜๊ณ  ์žˆ๋Š”๋ฐ ์ด๊ฒƒ์„ ์น˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค).

@joyt ๋ฌธ์ œ์˜ ๋†€์ดํ„ฐ ์žฌ๊ตฌ์„ฑ์„ ์ œ๊ณตํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ? ๋‚˜๋Š” react-redux๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š์ง€๋งŒ, ์•ž์„œ ์–ธ๊ธ‰ํ–ˆ๋“ฏ์ด ์œ ํ˜•์˜ ๋ชจ์–‘์— ๋Œ€ํ•ด ์›ํ•˜๋Š” ํ™•์žฅ์€ ์ธํ„ฐํŽ˜์ด์Šค ๋ณ‘ํ•ฉ์„ ์‚ฌ์šฉํ•˜์—ฌ ์„ ์–ธํ•  ์ˆ˜ ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

@masaeedu ๋Š” ์—ฌ๊ธฐ์—์„œ ์›€์ง์ด๋Š” ๋ถ€ํ’ˆ์˜ ๊ธฐ๋ณธ ๋ถ„๋ฅ˜์ž…๋‹ˆ๋‹ค.

๊ธฐ๋ณธ์ ์œผ๋กœ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋Š” React ๊ตฌ์„ฑ ์š”์†Œ์— ๋งŽ์€ ์†Œํ’ˆ์„ ์ œ๊ณตํ•˜๋ฏ€๋กœ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ์˜ ์ผ๋ฐ˜ ์œ ํ˜•์€ ์ƒ์œ„ ์ง‘ํ•ฉ์ด ์•„๋‹ˆ๋ผ ์žฅ์‹๋œ ๊ตฌ์„ฑ ์š”์†Œ์˜ ํ•˜์œ„ ์ง‘ํ•ฉ์ž…๋‹ˆ๋‹ค.

์ด๊ฒƒ์ด ๋„์›€์ด ๋˜๋Š”์ง€ ํ™•์‹คํ•˜์ง€ ์•Š์ง€๋งŒ ์‹คํ–‰ ๊ฐ€๋Šฅํ•œ ์œ ํ˜•์„ ๋ณด์—ฌ์ฃผ๊ธฐ ์œ„ํ•ด ์‹คํ–‰ํ•  ์ˆ˜ ์—†๋Š” ์ƒ˜ํ”Œ์„ ํ•จ๊ป˜ ๋งŒ๋“ค๋ ค๊ณ  ํ–ˆ์Šต๋‹ˆ๋‹ค.

// React types
class Component<TProps> {
    props: TProps
}
class ComponentClass<TProps> {
}
interface ComponentDecorator<TOriginalProps, TOwnProps> {
(component: ComponentClass<TOriginalProps>): ComponentClass<TOwnProps>;
}

// Redux types
interface MapStateToProps<TStateProps, TOwnProps> {
    (state: any, ownProps?: TOwnProps): TStateProps;
}

// Fake react create class
function createClass(component: any, props: any): any {
}

// Connect wraps the decorated component, providing a bunch of the properies
// So we want to return a ComponentDecorator which exposes LESS than
// the original component
function connect<TStateProps, TOwnProps>(
    mapStateToProps: MapStateToProps<TStateProps, TOwnProps>
): ComponentDecorator<TStateProps, TOwnProps> {
    return (ComponentClass) => {
        let mappedState = mapStateToProps({
            bar: 'bar value'
        })
        class Wrapped {
            render() {
                return createClass(ComponentClass, mappedState)
            }
        }

        return Wrapped
    }
}


// App Types
interface AllProps {
    foo: string
    bar: string
}

interface OwnProps {
    bar: string
}

// This does not work...
// @connect<AllProps, OwnProps>(state => state.foo)
// export default class MyComponent extends Component<AllProps> {
// }

// This does
class MyComponent extends Component<AllProps> {
}
export default connect<AllProps, OwnProps>(state => state.foo)(MyComponent)
//The type exported should be ComponentClass<OwnProps>,
// currently the decorator means we have to export ComponentClass<AllProps>

์ „์ฒด ์ž‘์—… ์˜ˆ์ œ๋ฅผ ์›ํ•˜๋ฉด https://github.com/jaysoo/todomvc-redux-react-typescript ๋˜๋Š” ๋‹ค๋ฅธ ์ƒ˜ํ”Œ react/redux/typescript ํ”„๋กœ์ ํŠธ๋ฅผ ํ’€๋‹ค์šดํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค.

https://github.com/wycats/javascript-decorators#class -declaration์— ๋”ฐ๋ฅด๋ฉด ์ œ์•ˆ๋œ declare type WrappingClassDecorator = <TFunction extends Function, TDecoratorFunction extends Function>(target: TFunction) => TDecoratorFunction; ์ด ์œ ํšจํ•˜์ง€ ์•Š๋‹ค๋Š” ๊ฒƒ์„ ์ดํ•ดํ•ฉ๋‹ˆ๋‹ค.

์‚ฌ์–‘์€ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋งํ•ฉ๋‹ˆ๋‹ค.

@F("color")
<strong i="6">@G</strong>
class Foo {
}

๋ฒˆ์—ญ:

var Foo = (function () {
  class Foo {
  }

  Foo = F("color")(Foo = G(Foo) || Foo) || Foo;
  return Foo;
})();

๋”ฐ๋ผ์„œ ๋‚ด๊ฐ€ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์ดํ•ดํ–ˆ๋‹ค๋ฉด ๋‹ค์Œ์ด ์‚ฌ์‹ค์ด์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

declare function F<T>(target: T): void;

<strong i="13">@F</strong>
class Foo {}

let a: Foo = new Foo(); // valid
class X {}
declare function F<T>(target: T): X;

<strong i="16">@F</strong>
class Foo {}

let a: X = new Foo(); // valid
let b: Foo = new Foo(); // INVALID
declare function F<T>(target: T): void;
declare function G<T>(target: T): void;

<strong i="19">@F</strong>
<strong i="20">@G</strong>
class Foo {}

let a: Foo = new Foo(); // valid
class X {}
declare function F<T>(target: T): void;
declare function G<T>(target: T): X;

<strong i="23">@F</strong>
<strong i="24">@G</strong>
class Foo {}

<strong i="25">@G</strong>
class Bar {}

<strong i="26">@F</strong>
class Baz {}

let a: Foo = new Foo(); // valid
let b: X = new Foo(); // INVALID
let c: X = new Bar(); // valid
let d: Bar = new Bar(); // INVALID
let e: Baz = new Baz(); // valid
class X {}
declare function F<T>(target: T): X;
declare function G<T>(target: T): void;

<strong i="29">@F</strong>
<strong i="30">@G</strong>
class Foo {}

<strong i="31">@G</strong>
class Bar {}

<strong i="32">@F</strong>
class Baz {}

let a: X = new Foo(); // valid
let b: Bar = new Bar(); // valid
let c: X = new Baz(); // valid
let d: Baz = new Baz(); // INVALID

@blai

๊ท€ํ•˜์˜ ์˜ˆ:

class X {}
declare function F<T>(target: T): X;

<strong i="9">@F</strong>
class Foo {}

let a: X = new Foo(); // valid
let b: Foo = new Foo(); // INVALID

F X ( X ์˜ ์ธ์Šคํ„ด์Šค๊ฐ€ ์•„๋‹˜)๋ฅผ ์ค€์ˆ˜ํ•˜๋Š” ํด๋ž˜์Šค๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•œ๋‹ค๊ณ  ๊ฐ€์ •ํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ:

declare function F<T>(target: T): typeof X;

์ด ๊ฒฝ์šฐ ์ฃผ์žฅ์€ ๋‹ค์Œ๊ณผ ๊ฐ™์•„์•ผ ํ•ฉ๋‹ˆ๋‹ค.

let a: X = new Foo(); // valid
let b: Foo = new Foo(); // valid

Foo let ๋Š” ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ์— ์˜ํ•ด ๋ณ€๊ฒฝ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ์›๋ž˜ Foo ์— ๋” ์ด์ƒ ์—ฐ๊ฒฐํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ๋‹ค์Œ๊ณผ ํšจ๊ณผ์ ์œผ๋กœ ๋™์ผํ•ฉ๋‹ˆ๋‹ค.

let Foo = F(class Foo {});

@nevir ๋„ค, ๋งž์Šต๋‹ˆ๋‹ค. ์„ค๋ช…ํ•ด์ฃผ์…”์„œ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค.

์ฐธ๊ณ ๋กœ, ๋Œ์—ฐ๋ณ€์ด๋œ ํด๋ž˜์Šค ์œ ํ˜•์„ ๋ฌดํšจํ™”ํ•˜๋Š” ๊ฒ€์‚ฌ๋ฅผ ๋„๋Š” ๊ฒƒ์€ ๋น„๊ต์  ์‰ฌ์šด ์ผ์ธ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts
index 06591a7..2320aff 100644
--- a/src/compiler/checker.ts
+++ b/src/compiler/checker.ts
@@ -11584,10 +11584,6 @@ namespace ts {
           */
         function getDiagnosticHeadMessageForDecoratorResolution(node: Decorator) {
             switch (node.parent.kind) {
-                case SyntaxKind.ClassDeclaration:
-                case SyntaxKind.ClassExpression:
-                    return Diagnostics.Unable_to_resolve_signature_of_class_decorator_when_called_as_an_expression;
-
                 case SyntaxKind.Parameter:
                     return Diagnostics.Unable_to_resolve_signature_of_parameter_decorator_when_called_as_an_expression;
         }

         /** Check a decorator */
        function checkDecorator(node: Decorator): void {
             const signature = getResolvedSignature(node);
             const returnType = getReturnTypeOfSignature(signature);
             if (returnType.flags & TypeFlags.Any) {
@@ -14295,9 +14291,7 @@ namespace ts {
             let errorInfo: DiagnosticMessageChain;
             switch (node.parent.kind) {
                 case SyntaxKind.ClassDeclaration:
-                    const classSymbol = getSymbolOfNode(node.parent);
-                    const classConstructorType = getTypeOfSymbol(classSymbol);
-                    expectedReturnType = getUnionType([classConstructorType, voidType]);
+                    expectedReturnType = returnType;
                     break;

                 case SyntaxKind.Parameter:
         }

๊ทธ๋Ÿฌ๋‚˜ ๋‚˜๋Š” ์ปดํŒŒ์ผ๋Ÿฌ๊ฐ€ ๋Œ์—ฐ๋ณ€์ด๋œ ํด๋ž˜์Šค์˜ ์˜ฌ๋ฐ”๋ฅธ ์œ ํ˜• ์ •์˜๋ฅผ ์ถœ๋ ฅํ•˜๋„๋ก ํ•  ๋งŒํผ ์ง€์‹์ด ์—†์Šต๋‹ˆ๋‹ค. ๋‹ค์Œ ํ…Œ์ŠคํŠธ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

ํ…Œ์ŠคํŠธ/์ผ€์ด์Šค/์ ํ•ฉ์„ฑ/๋ฐ์ฝ”๋ ˆ์ดํ„ฐ/ํด๋ž˜์Šค/decoratorOnClass10.ts

// <strong i="10">@target</strong>:es5
// <strong i="11">@experimentaldecorators</strong>: true
class X {}
class Y {}

declare function dec1<T>(target: T): T | typeof X;
declare function dec2<T>(target: T): typeof Y;

<strong i="12">@dec1</strong>
<strong i="13">@dec2</strong>
export default class C {
}

var c1: X | Y = new C();
var c2: X = new C();
var c3: Y = new C();

test/baselines/local/decoratorOnClass10.types๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.

=== tests/cases/conformance/decorators/class/decoratorOnClass10.ts ===
class X {}
>X : X

class Y {}
>Y : Y

declare function dec1<T>(target: T): T | typeof X;
>dec1 : <T>(target: T) => T | typeof X
>T : T
>target : T
>T : T
>T : T
>X : typeof X

declare function dec2<T>(target: T): typeof Y;
>dec2 : <T>(target: T) => typeof Y
>T : T
>target : T
>T : T
>Y : typeof Y

<strong i="17">@dec1</strong>
>dec1 : <T>(target: T) => T | typeof X

<strong i="18">@dec2</strong>
>dec2 : <T>(target: T) => typeof Y

export default class C {
>C : C
}

var c1: X | Y = new C();
>c1 : X | Y
>X : X
>Y : Y
>new C() : C
>C : typeof C

var c2: X = new C();
>c2 : X
>X : X
>new C() : C
>C : typeof C

var c3: Y = new C();
>c3 : Y
>Y : Y
>new C() : C
>C : typeof C

๋‚˜๋Š” ๊ธฐ๋Œ€ํ•˜๊ณ  ์žˆ์—ˆ๋‹ค
>C: typeof C ๋Š” >C: typeof X | typeof Y ๊ฐ€ ๋ฉ๋‹ˆ๋‹ค.

์ด ๊ธฐ๋Šฅ์— ๋Œ€ํ•œ ์‚ฌ๋ก€ ์—ฐ๊ตฌ๋กœ react-redux์˜ connect ์— ๊ด€์‹ฌ์ด ์žˆ๋Š” ์‚ฌ๋žŒ๋“ค์„ ์œ„ํ•ด ํ•œ ๊ณณ์—์„œ ๋ฌธ์ œ๋ฅผ ์ถ”์ ํ•˜๊ธฐ ์œ„ํ•ด https://github.com/DefinitelyTyped/DefinitelyTyped/issues/9951 ์„ ์ œ์ถœํ–ˆ์Šต๋‹ˆ๋‹ค.

๋‚˜๋Š” ์ด ๋ฌธ์ œ์— ๋Œ€ํ•œ ๋ชจ๋“  ๋Œ“๊ธ€์„ ์ฝ์—ˆ๊ณ  ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ์˜ ์„œ๋ช…์ด ์‹ค์ œ๋กœ ๋ž˜ํ•‘๋œ ํด๋ž˜์Šค๋กœ ๋ฌด์—‡์„ ํ•  ์ˆ˜ ์žˆ๋Š”์ง€ ๋ณด์—ฌ์ฃผ์ง€ ์•Š๋Š”๋‹ค๋Š” ์•„์ด๋””์–ด๋ฅผ ์–ป์—ˆ์Šต๋‹ˆ๋‹ค.

๋‹ค์Œ์„ ๊ณ ๋ คํ•˜์‹ญ์‹œ์˜ค.

function decorator(target) {
    target.prototype.someNewMethod = function() { ... };
    return new Wrapper(target);
}

๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ž…๋ ฅํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
declare function decorator<T>(target: T): Wrapper<T>;

๊ทธ๋Ÿฌ๋‚˜ ์ด ์„œ๋ช…์€ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๊ฐ€ ๋Œ€์ƒ์˜ ํ”„๋กœํ† ํƒ€์ž…์— ์ƒˆ๋กœ์šด ๊ฒƒ์„ ์ถ”๊ฐ€ํ–ˆ์Œ์„ ์•Œ๋ ค์ฃผ์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

๋ฐ˜๋ฉด์— ์ด๊ฒƒ์€ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๊ฐ€ ์‹ค์ œ๋กœ ๋ž˜ํผ๋ฅผ ๋ฐ˜ํ™˜ํ–ˆ๋‹ค๋Š” ์‚ฌ์‹ค์„ ์•Œ๋ ค์ฃผ์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
declare function decorator<T>(target: T): T & { someMethod: () => void };

์ด๊ฒƒ์— ๋Œ€ํ•œ ์†Œ์‹์ด ์žˆ์Šต๋‹ˆ๊นŒ? ์ด๊ฒƒ์€ ๋ฉ”ํƒ€ํ”„๋กœ๊ทธ๋ž˜๋ฐ์— ๋งค์šฐ ๊ฐ•๋ ฅํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค!

์ด ๋ฌธ์ œ์— ๋Œ€ํ•œ ๋” ๊ฐ„๋‹จํ•œ ์ ‘๊ทผ ๋ฐฉ์‹์€ ์–ด๋–ป์Šต๋‹ˆ๊นŒ? ๋ฐ์ฝ”๋ ˆ์ดํŒ…๋œ ํด๋ž˜์Šค์˜ ๊ฒฝ์šฐ ๊ตฌ๋ฌธ ์„คํƒ•์œผ๋กœ ํด๋ž˜์Šค ์ด๋ฆ„์„ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ ๋ฐ˜ํ™˜ ๊ฐ’์— ๋ฐ”์ธ๋”ฉํ•ฉ๋‹ˆ๋‹ค.

declare function Blah<T>(target: T): T & {foo: number}

<strong i="6">@Blah</strong>
class Foo {
    bar() {
        return this.foo; // Property 'foo' does not exist on type 'Foo'
    }
}

// is desugared to
const Foo = Blah(class Foo {
  // this.foo is not available here
})

new Foo.foo // foo is available here.

๊ตฌํ˜„ ์ธก๋ฉด์—์„œ ์ด๊ฒƒ์€ ๋ฐ์ฝ”๋ ˆ์ดํŒ…๋œ ํด๋ž˜์Šค์— ๋Œ€ํ•œ ํ•˜๋‚˜์˜ ํ•ฉ์„ฑ ๊ธฐํ˜ธ๋ฅผ ๋„์ž…ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์›๋ž˜ ํด๋ž˜์Šค ์ด๋ฆ„์€ ํด๋ž˜์Šค ๋ณธ๋ฌธ ๋ฒ”์œ„์—๋งŒ ๋ฐ”์ธ๋”ฉ๋ฉ๋‹ˆ๋‹ค.

@HerringtonDarkholme ์›ํ•˜๋Š” ํ‘œํ˜„๋ ฅ์„ ์ตœ๋Œ€ํ•œ ์ œ๊ณตํ•  ์ˆ˜ ์žˆ๋Š” ์‹ค์šฉ์ ์ด๊ณ  ์‹ค์šฉ์ ์ธ ์ ‘๊ทผ ๋ฐฉ์‹์ด๋ผ๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ์ข‹์€ ์•„์ด๋””์–ด!

์ด๊ฑด ์–ธ์  ๊ฐ€ ๊ผญ ๋ณด๊ณ ์‹ถ๋‹ค

์ €๋Š” ์ข…์ข… Angular 2 ๋˜๋Š” Aurelia์— ๋Œ€ํ•œ ํด๋ž˜์Šค๋ฅผ ์ž‘์„ฑํ•ฉ๋‹ˆ๋‹ค. ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

import {Http} from 'aurelia-fetch-client';
import {User} from 'models';

// accesses backend routes for 'api/user'
<strong i="9">@autoinject</strong> export default class UserService {
  constructor(readonly http : Http) { }

  readonly resourceUrl = 'api/users';

  async get(id: number) {
    const response = await this.http.fetch(this.resourceUrl);
    const user = await response.json() as User;
    return user;
  }

  async post(id: number, model: { [K in keyof User]?: User[K] }) {
    const response = await this.http.post(`${this.resourceUrl}/`${id}`, model);
    return await response.json();
  }
}

๋‚ด๊ฐ€ ์“ฐ๊ณ  ์‹ถ์€ ๊ฒƒ์€ ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.
๋ฐ์ฝ”๋ ˆ์ดํ„ฐ/api-client.ts

import {Http} from 'aurelia-fetch-client';

export type Target = { name; new (...args): { http: Http }};

export default function apiClient<T extends { id: string }>(resourceUrl: string) {
  return (target: Target)  => {
    type AugmentedTarget = Target & { get(id: number): Promise<T>, post(id, model: Partial<T>) };
    const t = target as AugmentedTarget;
    t.prototype.get = async function (id: number) {
      const response = await this.http.fetch(resourceUrl);
      return await response.json() as T;
    }
  }
}

๊ทธ๋Ÿฐ ๋‹ค์Œ ์ผ๋ฐ˜์ ์œผ๋กœ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

import {Http} from 'aurelia-fetch-client';
import apiClient from ./decorators/api-client
import {User} from 'models';

@apiClient<User>('api/users') export default class UserService {
  constructor(readonly http : Http) { }
}

์œ ํ˜• ์•ˆ์ „์„ฑ์˜ ์†์‹ค ์—†์ด. ์ด๊ฒƒ์€ ๊นจ๋—ํ•˜๊ณ  ํ‘œํ˜„๋ ฅ์ด ํ’๋ถ€ํ•œ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๋Š” ๋ฐ ๋„์›€์ด ๋  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์ด ๋ฌธ์ œ๋ฅผ ๋˜์‚ด๋ฆฌ์‹ญ์‹œ์˜ค.

์ด์ œ #13743์ด ๋‚˜์˜ค๊ณ  ๋ฏน์Šค์ธ ์ง€์›์ด ์–ธ์–ด๋กœ ์ œ๊ณต๋˜๋ฏ€๋กœ ์ด๊ฒƒ์€ ๋งค์šฐ ์œ ์šฉํ•œ ๊ธฐ๋Šฅ์ž…๋‹ˆ๋‹ค.

@HerringtonDarkholme ์€ ์ด ๊ฒฝ์šฐ์— ๋œ ์ ํ•ฉํ•˜์ง€๋งŒ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ์˜ ๋ฐ˜ํ™˜ ์œ ํ˜•์„ ์„ ์–ธํ•ด์•ผ ํ•˜๋Š” ์ผ๋ถ€ ๋™์  ๊ธฐ๋Šฅ์ด ๋Š์Šจํ•ด์ง‘๋‹ˆ๋‹ค...

@ahejlsberg , @mhegazy ์ด๊ฒƒ์ด ๊ฐ€๋Šฅํ•˜๋‹ค๊ณ  ์ƒ๊ฐํ•˜์‹ญ๋‹ˆ๊นŒ?

์•„์ง ํ™•์‹คํ•˜์ง€ ์•Š์€ ๋˜ ๋‹ค๋ฅธ ์‚ฌ์šฉ ์‹œ๋‚˜๋ฆฌ์˜ค๊ฐ€ ์žˆ์ง€๋งŒ ์ด ๋Œ€ํ™”์—์„œ ๋‹ค๋ฃจ์ง€๋งŒ ์•„๋งˆ๋„ ๊ฐ™์€ ๋ฒ”์ฃผ์— ์†ํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๋ฉ”์†Œ๋“œ์˜ ์œ ํ˜•์„ ์™„์ „ํžˆ ๋ณ€๊ฒฝํ•˜๋Š” ๋ฉ”์†Œ๋“œ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋ฅผ ๊ตฌํ˜„ํ•˜๊ณ  ์‹ถ์Šต๋‹ˆ๋‹ค(๋ฐ˜ํ™˜ ์œ ํ˜•์ด๋‚˜ ๋งค๊ฐœ๋ณ€์ˆ˜๊ฐ€ ์•„๋‹ˆ๋ผ ์ „์ฒด ํ•จ์ˆ˜). ์˜ˆ

type AsyncTask<Method extends Function> = {
    isRunning(): boolean;
} & Method;

// Decorator definition...
function asyncTask(target, methodName, descriptor) {
    ...
}

class Order {
    <strong i="7">@asyncTask</strong>
    async save(): Promise<void> {
        // Performs an async task and returns a promise
        ...
    }
}

const order = new Order();

order.save();
order.save.isRunning(); // Returns true

JavaScript์—์„œ๋Š” ์™„์ „ํžˆ ๊ฐ€๋Šฅํ•˜์ง€๋งŒ ๋ถ„๋ช…ํžˆ ๋ฌธ์ œ๋Š” ์•„๋‹ˆ์ง€๋งŒ TypeScript์—์„œ๋Š” ๋ฐ์ฝ”๋ ˆ์ดํŒ…๋œ ๋ฉ”์„œ๋“œ์˜ ์œ ํ˜•์„ () => Promise<void> ์—์„œ AsyncTask<() => Promise<void>> ๋กœ ๋ณ€๊ฒฝํ•˜๊ธฐ ์œ„ํ•ด asyncTask ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.

์ด๊ฒƒ์ด ์ง€๊ธˆ์€ ๋ถˆ๊ฐ€๋Šฅํ•˜๊ณ  ์•„๋งˆ๋„ ์ด ๋ฌธ์ œ์˜ ๋ฒ”์ฃผ์— ์†ํ•œ๋‹ค๊ณ  ํ™•์‹ ํ•ฉ๋‹ˆ๊นŒ?

@codeandcats ๊ท€ํ•˜์˜ ์˜ˆ๋Š” ์ œ๊ฐ€ ์—ฌ๊ธฐ์— ์žˆ๋Š” ๊ฒƒ๊ณผ ๋˜‘๊ฐ™์€ ์‚ฌ์šฉ ์‚ฌ๋ก€์ž…๋‹ˆ๋‹ค!

@ohjames ์•ˆ๋…•ํ•˜์„ธ์š”. ์‹ค๋ก€ํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ์‹œ๋ฅผ ๋”๋“ฌ๋Š” ๋ฐ ๋ฌธ์ œ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ๋†€์ดํ„ฐ์—์„œ์™€ ๊ฐ™์ด ์ž‘๋™ํ•˜๋Š” ๊ฒƒ์œผ๋กœ ๋‹ค์‹œ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ๋Š” ๊ธฐํšŒ๊ฐ€ ์žˆ์Šต๋‹ˆ๊นŒ?

์ด์— ๋Œ€ํ•œ ์ง„์ „์ด ์žˆ์Šต๋‹ˆ๊นŒ? ๋‚˜๋Š” ์ด ๋ฌธ์ œ๋ฅผ ๋ชจ๋ฅด๊ณ  ํ•˜๋ฃจ ์ข…์ผ ์ด๊ฒƒ์„ ๋จธ๋ฆฌ ์†์— ๊ฐ€์ง€๊ณ  ์žˆ์—ˆ๊ณ  ์ปดํŒŒ์ผ๋Ÿฌ๊ฐ€ ๊ทธ๊ฒƒ์„ ์„ ํƒํ•˜์ง€ ์•Š๋Š”๋‹ค๋Š” ๊ฒƒ์„ ์•Œ์•„๋‚ด๊ธฐ ์œ„ํ•ด ๊ทธ๊ฒƒ์„ ๊ตฌํ˜„ํ•˜๋Ÿฌ ๊ฐ”๋‹ค. ๋” ๋‚˜์€ ๋กœ๊น… ์†”๋ฃจ์…˜์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ํ”„๋กœ์ ํŠธ๊ฐ€ ์žˆ์œผ๋ฏ€๋กœ ๋‚˜์ค‘์— ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋ฅผ ํ†ตํ•ด ํด๋ž˜์Šค์— ์ฒจ๋ถ€ํ•  ๋ณธ๊ฒฉ์ ์ธ ๋กœ๊ฑฐ๋กœ ํ™•์žฅํ•˜๊ธฐ ์œ„ํ•ด ๋น ๋ฅธ ์‹ฑ๊ธ€ํ†ค์„ ์ž‘์„ฑํ–ˆ์Šต๋‹ˆ๋‹ค.

<strong i="6">@loggable</strong>
class Foo { }

ํ•„์š”ํ•œ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ–ˆ์Šต๋‹ˆ๋‹ค.

type Loggable<T> = T & { logger: Logger };

function loggable<T extends Function>(target: T): Loggable<T>
{
    Object.defineProperty(target.prototype, 'logger',
        { value: Logger.instance() });
    return <Loggable<T>> target;
}

๊ทธ๋ฆฌ๊ณ  logger ์†์„ฑ์€ ๋Ÿฐํƒ€์ž„์— ํ™•์‹คํžˆ ์กด์žฌํ•˜์ง€๋งŒ ์œ ๊ฐ์Šค๋Ÿฝ๊ฒŒ๋„ ์ปดํŒŒ์ผ๋Ÿฌ์— ์˜ํ•ด ์„ ํƒ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

ํŠนํžˆ ์ด์™€ ๊ฐ™์€ ๋Ÿฐํƒ€์ž„ ๊ตฌ์„ฑ์€ ์ปดํŒŒ์ผ ํƒ€์ž„์— ์ œ๋Œ€๋กœ ํ‘œ์‹œ๋  ์ˆ˜ ์žˆ์–ด์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ด ๋ฌธ์ œ์— ๋Œ€ํ•œ ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•์„ ๋ณด๊ณ  ์‹ถ์Šต๋‹ˆ๋‹ค.

๋‚˜๋Š” ์ง€๊ธˆ ๋‹น์žฅ ๋‚˜๋ฅผ ์–ป๊ธฐ ์œ„ํ•ด ์†์„ฑ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ์— ์ •์ฐฉํ–ˆ์Šต๋‹ˆ๋‹ค.

function logger<T>(target: T, key: string): void
{
    Object.defineProperty(target, 'logger',
        { value: Logger.instance() });
}

๋‹ค์Œ๊ณผ ๊ฐ™์€ ํด๋ž˜์Šค์— ์—ฐ๊ฒฐ

class Foo {
    <strong i="19">@logger</strong> private logger: Logger;
    ...

๊ทธ๋Ÿฌ๋‚˜ ์ด๊ฒƒ์€ ๋‹จ์ˆœํ•œ @loggable ํด๋ž˜์Šค ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋ณด๋‹ค ๋กœ๊ฑฐ๋ฅผ ํ™œ์šฉํ•˜๋Š” ํด๋ž˜์Šค๋‹น ํ›จ์”ฌ ๋” ๋งŽ์€ ์ƒ์šฉ๊ตฌ์ž…๋‹ˆ๋‹ค. (this as Loggable<this>).logger ์™€ ๊ฐ™์€ ํ˜•์‹ ๋ณ€ํ™˜์ด ๊ฐ€๋Šฅํ•˜๋‹ค๊ณ  ์ƒ๊ฐํ•˜์ง€๋งŒ ์ด๊ฒƒ์€ ํŠนํžˆ ๋ช‡ ๋ฒˆ ์ˆ˜ํ–‰ํ•œ ํ›„์—๋Š” ์ด์ƒ์ ์ด์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๊ทธ๊ฒƒ์€ ๋งค์šฐ ๋นจ๋ฆฌ ์ง€๊ฒจ์›Œ์งˆ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

https://github.com/jeffijoe/mobx-task ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๊ธฐ ๋•Œ๋ฌธ์— ์ „์ฒด ์•ฑ์— ๋Œ€ํ•ด TS๋ฅผ ์ˆ˜ํ–‰ํ•ด์•ผ ํ–ˆ์Šต๋‹ˆ๋‹ค. ์ด ๋ฌธ์ œ๊ฐ€ ๊ณง ํ•ด๊ฒฐ๋˜๊ธฐ๋ฅผ ๋ฐ”๋ž๋‹ˆ๋‹ค. ๐Ÿ˜„

๋ฐ์ฝ”๋ ˆ์ดํ„ฐ์™€ TypeScript๊ฐ€ ์ผ๊ธ‰ ์‹œ๋ฏผ์œผ๋กœ ์ทจ๊ธ‰๋˜๋Š” Angular 2 ์ƒํƒœ๊ณ„์—์„œ๋Š” ๋งค์šฐ ์งœ์ฆ๋‚ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋กœ ์†์„ฑ์„ ์ถ”๊ฐ€ํ•˜๋ ค๊ณ  ํ•˜๋Š” ์ˆœ๊ฐ„ TypeScript ์ปดํŒŒ์ผ๋Ÿฌ๋Š” ์•„๋‹ˆ์˜ค๋ผ๊ณ  ๋งํ•ฉ๋‹ˆ๋‹ค. Angular 2 ํŒ€์ด ์ด ๋ฌธ์ œ์— ์•ฝ๊ฐ„์˜ ๊ด€์‹ฌ์„ ๋ณด์ผ ๊ฒƒ์ด๋ผ๊ณ  ์ƒ๊ฐํ–ˆ์Šต๋‹ˆ๋‹ค.

@zajrik TS 2.2 ์ดํ›„ ์ ์ ˆํ•œ ํƒ€์ดํ•‘์ด ์ง€์›๋˜๋Š” ํด๋ž˜์Šค ๋ฏน์Šค์ธ์œผ๋กœ ์›ํ•˜๋Š” ๊ฒƒ์„ ๋‹ฌ์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋‹ค์Œ๊ณผ ๊ฐ™์ด Loggable ๋ฏน์Šค์ธ์„ ์ •์˜ํ•ฉ๋‹ˆ๋‹ค.

type Constructor<T> = new(...args: any[]) => T;

interface Logger {}

// You don't strictly need this interface, type inference will determine the shape of Loggable,
// you only need it if you want to refer to Loggable in a type position.
interface Loggable {
  logger: Logger;
}

function Loggable<T extends Constructor<object>>(superclass: T) {
  return class extends superclass {
    logger: Logger;
  };
}

๊ทธ๋Ÿฐ ๋‹ค์Œ ๋ช‡ ๊ฐ€์ง€ ๋ฐฉ๋ฒ•์œผ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํด๋ž˜์Šค ์„ ์–ธ์˜ extends ์ ˆ์—์„œ:

class Foo {
  superProperty: string;
}

class LoggableFoo extends Loggable(Foo) {
  subProperty: number;
}

TS๋Š” LoggableFoo superProperty , logger ๋ฐ subProperty ๊ฐ€ ์žˆ๋‹ค๋Š” ๊ฒƒ์„ ์•Œ๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

const o = new LoggableFoo();
o.superProperty; // string
o.logger; // Logger
o.subProperty; // number

๋ฏน์Šค์ธ์„ ์‚ฌ์šฉํ•˜๋ ค๋Š” ๊ตฌ์ฒด์ ์ธ ํด๋ž˜์Šค๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ํ‘œํ˜„์‹์œผ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

const LoggableFoo = Loggable(Foo);

๋˜ํ•œ ํด๋ž˜์Šค ๋ฏน์Šค์ธ์„ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ _์ˆ˜_ ์žˆ์ง€๋งŒ, ์•ฝ๊ฐ„ ๋‹ค๋ฅธ ์˜๋ฏธ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ์ฃผ๋กœ ํด๋ž˜์Šค๊ฐ€ ํด๋ž˜์Šค๋ฅผ ์„œ๋ธŒํด๋ž˜์‹ฑํ•˜๋„๋ก ํ—ˆ์šฉํ•˜๊ธฐ ๋ณด๋‹ค๋Š” ํด๋ž˜์Šค๋ฅผ ์„œ๋ธŒํด๋ž˜์Šค๋กœ ๋งŒ๋“œ๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

ํด๋ž˜์Šค ๋ฏน์Šค์ธ์€ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ(IMO)์— ๋น„ํ•ด ๋ช‡ ๊ฐ€์ง€ ์žฅ์ ์ด ์žˆ์Šต๋‹ˆ๋‹ค.

  1. ๊ทธ๋“ค์€ ์ƒˆ๋กœ์šด ์ˆ˜ํผ ํด๋ž˜์Šค๋ฅผ ์ƒ์„ฑํ•˜์—ฌ ์ ์šฉํ•œ ํด๋ž˜์Šค๊ฐ€ ์ด๋ฅผ ์žฌ์ •์˜ํ•˜๋Š” ๋ณ€๊ฒฝ ์‚ฌํ•ญ์„ ๊ฐ–๋„๋ก ํ•ฉ๋‹ˆ๋‹ค.
  2. TypeScript์˜ ์ถ”๊ฐ€ ๊ธฐ๋Šฅ ์—†์ด ์ง€๊ธˆ ์ž…๋ ฅ ํ™•์ธ
  3. ์œ ํ˜• ์œ ์ถ”์™€ ์ž˜ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค. mixin ํ•จ์ˆ˜์˜ ๋ฐ˜ํ™˜ ๊ฐ’์„ ์ž…๋ ฅํ•  ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.
  4. ๊ทธ๊ฒƒ๋“ค์€ ์ •์  ๋ถ„์„, ํŠนํžˆ jump-to-definition๊ณผ ์ž˜ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค logger ๊ตฌํ˜„์œผ๋กœ ์ ํ”„ํ•˜๋ฉด ์ธํ„ฐํŽ˜์ด์Šค๊ฐ€ ์•„๋‹Œ ๋ฏน์Šค์ธ _๊ตฌํ˜„_์œผ๋กœ ์ด๋™ํ•ฉ๋‹ˆ๋‹ค.

@justinfagnani ๋ฏน์Šค์ธ์„ ๊ณ ๋ คํ•˜์ง€๋„ ์•Š์•˜๋Š”๋ฐ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค. ์˜ค๋Š˜ ๋ฐค์— Loggable ๋ฏน์Šค์ธ์„ ์ž‘์„ฑํ•˜์—ฌ Logger ์ฒจ๋ถ€ ๊ตฌ๋ฌธ์„ ์ข€ ๋” ๋ฉ‹์ง€๊ฒŒ ๋งŒ๋“ค๊ฒ ์Šต๋‹ˆ๋‹ค. extends Mixin(SuperClass) ๊ฒฝ๋กœ๋Š” TS 2.2 ๋ฆด๋ฆฌ์Šค ์ดํ›„ ์ง€๊ธˆ๊นŒ์ง€ ๋ฏน์Šค์ธ์„ ์‚ฌ์šฉํ•œ ๋ฐฉ๋ฒ•์ด๋ฏ€๋กœ ์„ ํ˜ธํ•ฉ๋‹ˆ๋‹ค.

๊ทธ๋Ÿฌ๋‚˜ ๋‚˜๋Š” ๋ฏน์Šค์ธ๋ณด๋‹ค ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ ๊ตฌ๋ฌธ์ด๋ผ๋Š” ์•„์ด๋””์–ด๋ฅผ ์„ ํ˜ธํ•˜๋ฏ€๋กœ ์ด ํŠน์ • ๋ฌธ์ œ์— ๋Œ€ํ•ด ์•ฝ๊ฐ„์˜ ํ•ด๊ฒฐ์ฑ…์ด ์žˆ๊ธฐ๋ฅผ ์—ฌ์ „ํžˆ ํฌ๋งํ•ฉ๋‹ˆ๋‹ค. ๋‚ด ์ƒ๊ฐ์— ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ƒ์šฉ๊ตฌ ์—†๋Š” ๋ฏน์Šค์ธ์„ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์€ ์ฝ”๋“œ๋ฅผ ๊น”๋”ํ•˜๊ฒŒ ์ •๋ฆฌํ•˜๋Š” ๋ฐ ํฐ ๋„์›€์ด ๋  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

@zajrik ์ œ์•ˆ์ด ๋„์›€์ด ๋˜์–ด์„œ ๊ธฐ์ฉ๋‹ˆ๋‹ค.

๋‚˜๋Š” ์—ฌ์ „ํžˆ ๋ฏน์Šค์ธ์ด ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋ณด๋‹ค ๋” ๋งŽ์€ ์ƒ์šฉ๊ตฌ๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค๋Š” ๊ฒƒ์„ ์ดํ•ดํ•˜์ง€ ๋ชปํ•ฉ๋‹ˆ๋‹ค. ๋ฌธ๋ฒ•์  ๊ฐ€์ค‘์น˜๋Š” ๊ฑฐ์˜ ๋™์ผํ•ฉ๋‹ˆ๋‹ค.

ํด๋ž˜์Šค ๋ฏน์‹ :

class LoggableFoo extends Loggable(Foo) {}

๋Œ€ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ:

<strong i="12">@Loggable</strong>
class LoggableFoo extends Foo {}

์ œ ์ƒ๊ฐ์—๋Š” ๋ฏน์Šค์ธ์ด ๊ทธ ์˜๋„์— ๋Œ€ํ•ด ํ›จ์”ฌ ๋” ๋ช…ํ™•ํ•ฉ๋‹ˆ๋‹ค. ์Šˆํผํด๋ž˜์Šค๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ์Šˆํผํด๋ž˜์Šค๊ฐ€ ํด๋ž˜์Šค์˜ ๋ฉค๋ฒ„๋ฅผ ์ •์˜ํ•˜๋ฏ€๋กœ ๋ฏน์Šค์ธ๋„ ๋ฉค๋ฒ„๋ฅผ ์ •์˜ํ•˜๊ณ  ์žˆ์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋Š” ๋ฉค๋ฒ„๋ฅผ ์ •์˜ํ•˜๊ฑฐ๋‚˜ ์ •์˜ํ•˜์ง€ ์•Š๋Š”๋‹ค๊ณ  ๊ฐ€์ •ํ•  ์ˆ˜ ์—†๋Š” ๋งŽ์€ ์ผ์— ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค. ๋‹จ์ˆœํžˆ ํด๋ž˜์Šค๋ฅผ ๋“ฑ๋กํ•˜๊ฑฐ๋‚˜ ์ผ๋ถ€ ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ๋ฅผ ์—ฐ๊ฒฐํ•˜๋Š” ๊ฒƒ์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ณต์ •ํ•˜๊ฒŒ ๋งํ•˜๋ฉด @zajrik ์ด ์›ํ•˜๋Š” ๊ฒƒ์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

<strong i="7">@loggable</strong>
class Foo { }

์ด๊ฒƒ์€ ๋ถ€์ธํ•  ์ˆ˜ ์—†์ง€๋งŒ ์•ฝ๊ฐ„์ด๋ผ๋„ ์ƒ์šฉ๊ตฌ๊ฐ€ ์ ์Šต๋‹ˆ๋‹ค.

์ฆ‰, ๋‚˜๋Š” mixin ์†”๋ฃจ์…˜์„ ์ข‹์•„ํ•ฉ๋‹ˆ๋‹ค. ๋ฏน์Šค์ธ์ด ์ค‘์š”ํ•˜๋‹ค๋Š” ์‚ฌ์‹ค์„ ๊ณ„์† ์žŠ๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

ํ˜„์žฌ ํด๋ž˜์Šค์— ์†์„ฑ์„ ์ถ”๊ฐ€ํ•˜๋Š” ๊ฒƒ์—๋งŒ ๊ด€์‹ฌ์ด ์žˆ๋‹ค๋ฉด ๋ฏน์Šค์ธ์€ ๊ธฐ๋ณธ์ ์œผ๋กœ ํ•œ ๊ฐ€์ง€ ์‹ฌ๊ฐํ•œ ๋ฌธ์ œ๊ฐ€ ์žˆ๋Š” ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ์™€ ๋™์ผํ•ฉ๋‹ˆ๋‹ค... ํด๋ž˜์Šค์— ์•„์ง ์Šˆํผํด๋ž˜์Šค๊ฐ€ ์—†์œผ๋ฉด ์ด๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด ๋นˆ ์Šˆํผํด๋ž˜์Šค๋ฅผ ๋งŒ๋“ค์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๋˜ํ•œ ๊ตฌ๋ฌธ์€ ์ผ๋ฐ˜์ ์œผ๋กœ ๋” ๋ฌด๊ฑฐ์›Œ ๋ณด์ž…๋‹ˆ๋‹ค. ๋˜ํ•œ ๋งค๊ฐœ๋ณ€์ˆ˜ ๋ฏน์Šค์ธ์ด ์ง€์›๋˜๋Š”์ง€ ์—ฌ๋ถ€๋„ ๋ช…ํ™•ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค( extends Mixin(Class, { ... }) ํ—ˆ์šฉ).

์ด์œ  ๋ชฉ๋ก์—์„œ @justinfagnani , ํฌ์ธํŠธ 2-4๋Š” ์‹ค์ œ๋กœ ๋ฏน์Šค์ธ์˜ ์žฅ์ ์ด ์•„๋‹ˆ๋ผ TypeScript์˜ ๊ฒฐํ•จ์ž…๋‹ˆ๋‹ค. JS ์„ธ๊ณ„์—์„œ๋Š” ์ ์šฉ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

OP ๋ฌธ์ œ์— ๋Œ€ํ•œ ๋ฏน์Šค์ธ ๊ธฐ๋ฐ˜ ์†”๋ฃจ์…˜์—๋Š” ํ”„๋กœํ† ํƒ€์ž… ์ฒด์ธ์— ๋‘ ๊ฐœ์˜ ํด๋ž˜์Šค๋ฅผ ์ถ”๊ฐ€ํ•˜๋Š” ๊ฒƒ์ด ํฌํ•จ๋˜๋ฉฐ ๊ทธ ์ค‘ ํ•˜๋‚˜๋Š” ์“ธ๋ชจ๊ฐ€ ์—†๋‹ค๋Š” ๊ฒƒ์„ ์šฐ๋ฆฌ ๋ชจ๋‘ ๋ถ„๋ช…ํžˆ ํ•ด์•ผ ํ•œ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ ๋ฏน์Šค์ธ ๋Œ€ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ์˜ ์˜๋ฏธ๋ก ์  ์ฐจ์ด๋ฅผ ๋ฐ˜์˜ํ•˜์ง€๋งŒ, ๋ฏน์Šค์ธ์€ ๋ถ€๋ชจ ํด๋ž˜์Šค ์ฒด์ธ์„ ๊ฐ€๋กœ์ฑŒ ๊ธฐํšŒ๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ 95%์˜ ์‹œ๊ฐ„์€ ์‚ฌ๋žŒ๋“ค์ด ํ•˜๊ณ  ์‹ถ์€ ๊ฒƒ์ด ์•„๋‹ˆ๋ผ ์ด ์ˆ˜์—…์„ ๊พธ๋ฏธ๊ณ  ์‹ถ์–ดํ•ฉ๋‹ˆ๋‹ค. ๋ฏน์Šค์ธ์€ ์šฉ๋„๊ฐ€ ์ œํ•œ์ ์ด์ง€๋งŒ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ ๋ฐ ์ƒ์œ„ ํด๋ž˜์Šค์— ๋Œ€ํ•œ ๋Œ€์•ˆ์œผ๋กœ ๋ฏน์Šค์ธ์„ ํ™๋ณดํ•˜๋Š” ๊ฒƒ์€ ์˜๋ฏธ์ƒ ๋ถ€์ ์ ˆํ•˜๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

๋ฏน์Šค์ธ์€ ๊ธฐ๋ณธ์ ์œผ๋กœ ํ•œ ๊ฐ€์ง€ ์ค‘์š”ํ•œ ์„ฑ๊ฐ€์‹ฌ์œผ๋กœ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ์™€ ๋™์ผํ•ฉ๋‹ˆ๋‹ค... ํด๋ž˜์Šค์— ์•„์ง ์ˆ˜ํผํด๋ž˜์Šค๊ฐ€ ์—†์œผ๋ฉด ์ด๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด ๋นˆ ์ˆ˜ํผํด๋ž˜์Šค๋ฅผ ์ƒ์„ฑํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

์ด๊ฒƒ์€ ๋ฐ˜๋“œ์‹œ ์‚ฌ์‹ค์€ ์•„๋‹™๋‹ˆ๋‹ค.

function Mixin(superclass = Object) { ... }

class Foo extends Mixin() {}

๋˜ํ•œ ๊ตฌ๋ฌธ์€ ์ผ๋ฐ˜์ ์œผ๋กœ ๋” ๋ฌด๊ฑฐ์›Œ ๋ณด์ž…๋‹ˆ๋‹ค.

๋‚˜๋Š” ์ด๊ฒƒ์ด ์–ด๋–ป๊ฒŒ ๋˜๋Š”์ง€ ์•Œ์ง€ ๋ชปํ•˜๋ฏ€๋กœ ์šฐ๋ฆฌ๋Š” ๋™์˜ํ•˜์ง€ ์•Š์„ ์ˆ˜ ๋ฐ–์— ์—†์Šต๋‹ˆ๋‹ค.

๋˜ํ•œ ๋งค๊ฐœ๋ณ€์ˆ˜ ๋ฏน์Šค์ธ์ด ์ง€์›๋˜๋Š”์ง€ ์—ฌ๋ถ€๋„ ๋ช…ํ™•ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค(Mixin(Class, { ... }) ํ™•์žฅ์ด ํ—ˆ์šฉ๋จ).

๊ทธ๋“ค์€ ์•„์ฃผ ๋งŽ์ด ์žˆ์Šต๋‹ˆ๋‹ค. ๋ฏน์Šค์ธ์€ ํ•จ์ˆ˜์ผ ๋ฟ์ž…๋‹ˆ๋‹ค.

์ด์œ  ๋ชฉ๋ก์—์„œ ํฌ์ธํŠธ 2-4๋Š” ์‹ค์ œ๋กœ ๋ฏน์Šค์ธ์˜ ์žฅ์ ์ด ์•„๋‹ˆ๋ผ TypeScript์˜ ๊ฒฐํ•จ์ž…๋‹ˆ๋‹ค. JS ์„ธ๊ณ„์—์„œ๋Š” ์ ์šฉ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์ด๊ฒƒ์€ TypeScript ๋ฌธ์ œ์ด๋ฏ€๋กœ ์—ฌ๊ธฐ์— ์ ์šฉ๋ฉ๋‹ˆ๋‹ค. JS ์„ธ๊ณ„์—์„œ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋Š” ์•„์ง ์‹ค์ œ๋กœ ์กด์žฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

OP ๋ฌธ์ œ์— ๋Œ€ํ•œ ๋ฏน์Šค์ธ ๊ธฐ๋ฐ˜ ์†”๋ฃจ์…˜์—๋Š” ํ”„๋กœํ† ํƒ€์ž… ์ฒด์ธ์— ๋‘ ๊ฐœ์˜ ํด๋ž˜์Šค๋ฅผ ์ถ”๊ฐ€ํ•˜๋Š” ๊ฒƒ์ด ํฌํ•จ๋˜๋ฉฐ ๊ทธ ์ค‘ ํ•˜๋‚˜๋Š” ์“ธ๋ชจ๊ฐ€ ์—†๋‹ค๋Š” ๊ฒƒ์„ ์šฐ๋ฆฌ ๋ชจ๋‘ ๋ถ„๋ช…ํžˆ ํ•ด์•ผ ํ•œ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

2๊ฐœ๋Š” ์–ด๋””์„œ ๊ตฌํ•˜์‹œ๋Š”์ง€ ๋ชจ๋ฅด๊ฒ ๋„ค์š”. ํŒจ์น˜๋ฅผ ํ•˜์ง€ ์•Š๋Š” ํ•œ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๊ฐ€ ํ•˜๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ํ•˜๋‚˜์ž…๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์–ด๋–ค ํ”„๋กœํ† ํƒ€์ž…์ด ์“ธ๋ชจ๊ฐ€ ์—†์Šต๋‹ˆ๊นŒ? mixin ์‘์šฉ ํ”„๋กœ๊ทธ๋žจ์€ ์•„๋งˆ๋„ ์“ธ๋ชจ์—†๋Š” ์†์„ฑ/๋ฉ”์†Œ๋“œ๋ฅผ ์ถ”๊ฐ€ํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์ด๊ฒƒ์€ ๋ฏน์Šค์ธ ๋Œ€ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ์˜ ์˜๋ฏธ๋ก ์  ์ฐจ์ด๋ฅผ ๋ฐ˜์˜ํ•˜์ง€๋งŒ, ๋ฏน์Šค์ธ์€ ๋ถ€๋ชจ ํด๋ž˜์Šค ์ฒด์ธ์„ ๊ฐ€๋กœ์ฑŒ ๊ธฐํšŒ๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ 95%์˜ ์‹œ๊ฐ„์€ ์‚ฌ๋žŒ๋“ค์ด ํ•˜๊ณ  ์‹ถ์€ ๊ฒƒ์ด ์•„๋‹ˆ๋ผ ์ด ์ˆ˜์—…์„ ๊พธ๋ฏธ๊ณ  ์‹ถ์–ดํ•ฉ๋‹ˆ๋‹ค.

์ด๊ฒƒ์ด ์‚ฌ์‹ค์ธ์ง€ ํ™•์‹ ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ์ผ๋ฐ˜์ ์œผ๋กœ ํด๋ž˜์Šค๋ฅผ ์ •์˜ํ•  ๋•Œ ์ƒ์œ„ ํด๋ž˜์Šค ๋ฉ”์„œ๋“œ๋ฅผ ์žฌ์ •์˜ํ•  ์ˆ˜ ์žˆ๋Š” ๊ธฐ๋Šฅ๊ณผ ํ•จ๊ป˜ ์ƒ์† ๊ณ„์ธต์˜ ๋งจ ์•„๋ž˜์— ์žˆ์„ ๊ฒƒ์œผ๋กœ ์˜ˆ์ƒํ•ฉ๋‹ˆ๋‹ค. ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋Š” super() ๋กœ ์ž‘๋™ํ•˜์ง€ ์•Š๋Š” ๊ฒƒ์„ ํฌํ•จํ•˜์—ฌ ์ˆ˜๋งŽ์€ ๋ฌธ์ œ๊ฐ€ ์žˆ๋Š” ํด๋ž˜์Šค๋ฅผ ํŒจ์น˜ํ•˜๊ฑฐ๋‚˜ ํ™•์žฅํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ด ๊ฒฝ์šฐ ๋ฐ์ฝ”๋ ˆ์ดํŠธ๋œ ํด๋ž˜์Šค๋Š” ํ™•์žฅ์„ ์žฌ์ •์˜ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ ์„ฑ๋Šฅ/๋””๋ฒ„๊น… ์ถ”์ ์„ ์œ„ํ•ด ํด๋ž˜์Šค์˜ ์ •์˜๋œ ๋ชจ๋“  ๋ฉ”์„œ๋“œ๋ฅผ ์žฌ์ •์˜ํ•˜๋Š” ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ์™€ ๊ฐ™์€ ์ผ๋ถ€ ๊ฒฝ์šฐ์— ์œ ์šฉํ•  ์ˆ˜ ์žˆ์ง€๋งŒ ์ผ๋ฐ˜์ ์ธ ์ƒ์† ๋ชจ๋ธ๊ณผ๋Š” ๊ฑฐ๋ฆฌ๊ฐ€ ๋ฉ‰๋‹ˆ๋‹ค.

๋ฏน์Šค์ธ์€ ์šฉ๋„๊ฐ€ ์ œํ•œ์ ์ด์ง€๋งŒ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ ๋ฐ ์ƒ์œ„ ํด๋ž˜์Šค์— ๋Œ€ํ•œ ๋Œ€์•ˆ์œผ๋กœ ๋ฏน์Šค์ธ์„ ํ™๋ณดํ•˜๋Š” ๊ฒƒ์€ ์˜๋ฏธ์ƒ ๋ถ€์ ์ ˆํ•˜๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

๊ฐœ๋ฐœ์ž๊ฐ€ ํ”„๋กœํ† ํƒ€์ž… ์ฒด์ธ์— ๋ฉค๋ฒ„๋ฅผ ์ถ”๊ฐ€ํ•˜๋ ค๊ณ  ํ•  ๋•Œ ๋ฏน์Šค์ธ์€ ์ •ํ™•ํžˆ ์˜๋ฏธ์ƒ ์ ์ ˆํ•ฉ๋‹ˆ๋‹ค. ๋ˆ„๊ตฐ๊ฐ€๊ฐ€ ๋ฏน์Šค์ธ์— ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋ฅผ ์‚ฌ์šฉํ•˜๋ ค๋Š” ๊ฒƒ์„ ๋ณธ ๋ชจ๋“  ๊ฒฝ์šฐ์— ํด๋ž˜์Šค ๋ฏน์Šค์ธ์„ ์‚ฌ์šฉํ•˜๋ฉด ์‹ค์ œ๋กœ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ์—์„œ ๊ธฐ๋Œ€ํ•˜๋Š” ์˜๋ฏธ ์ฒด๊ณ„, ์ˆ˜ํผ ํ˜ธ์ถœ์ด ์žˆ๋Š” ์ž‘์—… ์†์„ฑ์œผ๋กœ ์ธํ•ด ๋” ๋งŽ์€ ์œ ์—ฐ์„ฑ์„ ์‚ฌ์šฉํ•˜์—ฌ ๋™์ผํ•œ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋ฌผ๋ก  ๊ทธ๋“ค์€ ์ง€๊ธˆ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค.

๋ฏน์Šค์ธ์€ ์‚ฌ์šฉ ์‚ฌ๋ก€๋ฅผ ์ง์ ‘ ๋‹ค๋ฃฐ ๋•Œ ๋ถ€์ ์ ˆํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

๊ฐœ๋ฐœ์ž๊ฐ€ ํ”„๋กœํ† ํƒ€์ž… ์ฒด์ธ์— ๊ตฌ์„ฑ์›์„ ์ถ”๊ฐ€ํ•˜๋ ค๋Š” ๊ฒฝ์šฐ

๊ทธ๊ฒƒ์ด ๋ฐ”๋กœ ์ œ ์š”์ ์ž…๋‹ˆ๋‹ค. OP๋Š” ํ”„๋กœํ† ํƒ€์ž… ์ฒด์ธ์— ์•„๋ฌด ๊ฒƒ๋„ ์ถ”๊ฐ€ํ•˜๊ณ  ์‹ถ์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๊ทธ๋Š” ๋‹จ์ง€ ๋‹จ์ผ ํด๋ž˜์Šค๋ฅผ ๋ณ€๊ฒฝํ•˜๊ธฐ๋ฅผ ์›ํ•˜๋ฉฐ ๋Œ€๋ถ€๋ถ„ ์‚ฌ๋žŒ๋“ค์ด ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ Object ์ด์™ธ์˜ ์ƒ์œ„ ํด๋ž˜์Šค๋„ ๊ฐ–์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์–ด๋–ค ์ด์œ ๋กœ Mixin(Object) ๋Š” TypeScript์—์„œ ์ž‘๋™ํ•˜์ง€ ์•Š์œผ๋ฏ€๋กœ ๋”๋ฏธ ๋นˆ ํด๋ž˜์Šค๋ฅผ ์ถ”๊ฐ€ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ด์ œ ํ•„์š”ํ•˜์ง€ ์•Š์„ ๋•Œ 2์˜ ํ”„๋กœํ† ํƒ€์ž… ์ฒด์ธ(Object ์ œ์™ธ)์ด ์žˆ์Šต๋‹ˆ๋‹ค. ๋˜ํ•œ ํ”„๋กœํ† ํƒ€์ž… ์ฒด์ธ์— ์ƒˆ ํด๋ž˜์Šค๋ฅผ ์ถ”๊ฐ€ํ•˜๋Š” ๋ฐ๋Š” ์ ์ง€ ์•Š์€ ๋น„์šฉ์ด ๋“ญ๋‹ˆ๋‹ค.

๊ตฌ๋ฌธ ๋น„๊ต Mixin1(Mixin2(Mixin3(Object, { ... }), {... }), {...}) . ๊ฐ ๋ฏน์Šค์ธ์˜ ๋งค๊ฐœ๋ณ€์ˆ˜๋Š” ๊ฐ€๋Šฅํ•œ ํ•œ ๋ฏน์Šค์ธ ํด๋ž˜์Šค์—์„œ ๋ฉ€๋ฆฌ ๋–จ์–ด์ ธ ์žˆ์Šต๋‹ˆ๋‹ค. ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ ๊ตฌ๋ฌธ์€ ๋ถ„๋ช…ํžˆ ๋” ์ฝ๊ธฐ ์‰ฝ์Šต๋‹ˆ๋‹ค.

๋ฐ์ฝ”๋ ˆ์ดํ„ฐ ๊ตฌ๋ฌธ ์ž์ฒด๋Š” ์œ ํ˜• ๊ฒ€์‚ฌ๊ฐ€ ์•„๋‹ˆ์ง€๋งŒ ์ผ๋ฐ˜ ํ•จ์ˆ˜ ํ˜ธ์ถœ์„ ์‚ฌ์šฉํ•˜์—ฌ ์›ํ•˜๋Š” ๊ฒƒ์„ ์–ป์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

class Logger { static instance() { return new Logger(); } }
type Loggable<T> = T & { logger: Logger };
function loggable<T, U>(target: { new (): T } & U): { new (): Loggable<T> } & U
{
    // ...
}

const Foo = loggable(class {
    x: string
});

let foo = new Foo();
foo.logger; // Logger
foo.x; // string

ํด๋ž˜์Šค๋ฅผ const Foo = loggable(class { ๋กœ ์„ ์–ธํ•ด์•ผ ํ•˜๋Š” ๊ฒƒ์€ ์•ฝ๊ฐ„ ์งœ์ฆ๋‚˜์ง€๋งŒ ๊ทธ ์™ธ์—๋Š” ๋ชจ๋‘ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค.

@ohjames (cc @justinfagnani) Object ์™€ ๊ฐ™์€ ๋‚ด์žฅ ๊ธฐ๋Šฅ์„ ํ™•์žฅํ•  ๋•Œ ์ฃผ์˜ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค(์ธ์Šคํ„ด์Šค์—์„œ ํ•˜์œ„ ํด๋ž˜์Šค์˜ ํ”„๋กœํ† ํƒ€์ž…์„ ๊ฐ•ํƒ€ํ•˜๊ธฐ ๋•Œ๋ฌธ์—): https://github.com/Microsoft/TypeScript/wiki/FAQ #์™œ -extending -built-ins-like-error-array-and-map-work๊ฐ€ ์ž‘๋™ํ•˜์ง€ ์•Š๋Š”์ง€

@nevir ๋„ค, ์ €๋Š” ์ด๋ฏธ TypeScript 2.2์—์„œ ๊ธฐ๋ณธ Object ๋งค๊ฐœ๋ณ€์ˆ˜์™€ ํ•จ๊ป˜ mixin์„ ์‚ฌ์šฉ ํ•˜๋ผ๋Š” @justinfagnani ์˜ ์ œ์•ˆ์„ ์ด๋ฏธ ์‹œ๋„ํ–ˆ์ง€๋งŒ tsc๋Š” ์ฝ”๋“œ๋ฅผ ๊ฑฐ๋ถ€ํ–ˆ์Šต๋‹ˆ๋‹ค.

@ohjames ์—ฌ์ „ํžˆ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค. ๊ธฐ๋ณธ ์ผ€์ด์Šค์˜ ํ”„๋กœํ† ํƒ€์ž…์— ๋Œ€ํ•ด ์ฃผ์˜ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค(FAQ ํ•ญ๋ชฉ ์ฐธ์กฐ).

๊ทธ๋Ÿฌ๋‚˜ ์ผ๋ฐ˜์ ์œผ๋กœ null ์ „๋‹ฌ๋  ๋•Œ tslib.__extend ์˜ ๋™์ž‘์— ์˜์กดํ•˜๋Š” ๊ฒƒ์ด ๋” ์‰ฝ์Šต๋‹ˆ๋‹ค.

๋‹ค์Œ ๋ฐ˜๋ณต ๋‹จ๊ณ„์—์„œ ์ด ๋ฌธ์ œ์— ์ง‘์ค‘ํ•  ๊ณ„ํš์ด ์žˆ์Šต๋‹ˆ๊นŒ? ์ด ๊ธฐ๋Šฅ์˜ ์ด์ ์€ ๋งŽ์€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์—์„œ ๋งค์šฐ ๋†’๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๋ฐฉ๊ธˆ ์ด ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค. ๋ถˆํ•„์š”ํ•œ ์ฝ”๋“œ๋ฅผ ๋งŽ์ด ์ž‘์„ฑํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๋Š” ๊ฒƒ์€ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ ๊ธฐ๋ฐ˜ ํ”„๋ ˆ์ž„์›Œํฌ/๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์— ํฐ ๋„์›€์ด ๋  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

@TomMarius ์•ž์„œ ์–ธ๊ธ‰ํ–ˆ๋“ฏ์ด ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ ํ•จ์ˆ˜๋กœ ๋ž˜ํ•‘๋œ ํด๋ž˜์Šค๋Š” ์ด๋ฏธ ์œ ํ˜• ๊ฒ€์‚ฌ๋ฅผ ์ œ๋Œ€๋กœ ์ˆ˜ํ–‰ํ•˜๋ฏ€๋กœ @ ๊ตฌ๋ฌธ ์„คํƒ•์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ๋Œ€์‹ :

<strong i="8">@loggable</strong>
class Foo { }

๋‹ค์Œ์„ ์ˆ˜ํ–‰ํ•˜๊ธฐ๋งŒ ํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.

const Foo = loggable(class { });

ํด๋ž˜์Šค๋ฅผ ๋ž˜ํ•‘ํ•˜๊ธฐ ์ „์— ์—ฌ๋Ÿฌ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ ํ•จ์ˆ˜๋ฅผ ํ•จ๊ป˜ ๊ตฌ์„ฑํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ตฌ๋ฌธ ์„คํƒ•์ด ์ œ๋Œ€๋กœ ์ž‘๋™ํ•˜๋„๋ก ํ•˜๋Š” ๊ฒƒ์ด ์ค‘์š”ํ•˜์ง€๋งŒ ์ด๊ฒƒ์ด ์‹ค์ œ๋กœ ๊ทธ๋ ‡๊ฒŒ ํฐ ๋ฌธ์ œ๊ฐ€ ๋˜์–ด์•ผ ํ•˜๋Š” ๊ฒƒ ๊ฐ™์ง€๋Š” ์•Š์Šต๋‹ˆ๋‹ค.

@masaeedu ์ •๋ง ๋ฌธ์ œ๋Š” ์™ธ๋ถ€๊ฐ€ ์•„๋‹ˆ๋ผ ๋‚ด๋ถ€ ์œ ํ˜• ์ง€์›์ž…๋‹ˆ๋‹ค. ์ปดํŒŒ์ผ ์˜ค๋ฅ˜ ์—†์ด ํด๋ž˜์Šค ์ž์ฒด์— ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๊ฐ€ ์ถ”๊ฐ€ํ•˜๋Š” ์†์„ฑ์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์€ ์ ์–ด๋„ ๋‚˜์—๊ฒŒ๋Š” ์›ํ•˜๋Š” ๊ฒฐ๊ณผ์ž…๋‹ˆ๋‹ค. ๊ท€ํ•˜๊ฐ€ ์ œ๊ณตํ•œ ์˜ˆ์ œ๋Š” Foo ์— ๊ธฐ๋ก ๊ฐ€๋Šฅํ•œ ์œ ํ˜•๋งŒ ์ œ๊ณตํ•˜์ง€๋งŒ ํด๋ž˜์Šค ์ •์˜ ์ž์ฒด์—๋Š” ์œ ํ˜•์„ ์ œ๊ณตํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

@zajrik ๋‚ด์žฅ @ ๊ตฌ๋ฌธ์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ์—๋„ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋Š” ์›๋ž˜ ํด๋ž˜์Šค์—์„œ ์ƒˆ ํด๋ž˜์Šค๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. ๋ถ„๋ช…ํžˆ JS๋Š” ์ˆœ์ˆ˜์„ฑ์„ ๊ฐ•์š”ํ•˜์ง€ ์•Š์œผ๋ฏ€๋กœ ์ „๋‹ฌํ•œ ์›๋ž˜ ํด๋ž˜์Šค๋ฅผ ์ž์œ ๋กญ๊ฒŒ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ์ง€๋งŒ ์ด๋Š” ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ ๊ฐœ๋…์˜ ๊ด€์šฉ์  ์‚ฌ์šฉ๊ณผ ์ผ์น˜ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋ฅผ ํ†ตํ•ด ํด๋ž˜์Šค ๋‚ด๋ถ€์— ์ถ”๊ฐ€ํ•˜๋Š” ๊ธฐ๋Šฅ์„ ๊ธด๋ฐ€ํ•˜๊ฒŒ ์—ฐ๊ฒฐํ•˜๋Š” ๊ฒฝ์šฐ ๋‚ด๋ถ€ ์†์„ฑ์ผ ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

๋‚˜์ค‘์— ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋ฅผ ํ†ตํ•ด ์ถ”๊ฐ€๋˜๋Š” ๋‚ด๋ถ€์ ์œผ๋กœ API๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ํด๋ž˜์Šค์— ๋Œ€ํ•œ ์‚ฌ์šฉ ์‚ฌ๋ก€์˜ ์˜ˆ๋ฅผ ์ œ๊ณตํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ?

์œ„์˜ ๋กœ๊ฑฐ ์˜ˆ์ œ๋Š” ๋ฐ์ฝ”๋ ˆ์ดํŒ…๋œ ํด๋ž˜์Šค์˜ ๋‚ด๋ถ€๋ฅผ ์กฐ์ž‘ํ•  ์ˆ˜ ์žˆ๋Š” ์ผ๋ฐ˜์ ์ธ _want_์˜ ์ข‹์€ ์˜ˆ์ž…๋‹ˆ๋‹ค. (๊ทธ๋ฆฌ๊ณ  Python๊ณผ ๊ฐ™์€ ํด๋ž˜์Šค ๋ฐ์ฝ”๋ ˆ์ด์…˜์ด ์žˆ๋Š” ๋‹ค๋ฅธ ์–ธ์–ด์—์„œ ์˜จ ์‚ฌ๋žŒ๋“ค์—๊ฒŒ ์นœ์ˆ™ํ•ฉ๋‹ˆ๋‹ค.)

์ฆ‰, @justinfagnani ์˜ ํด๋ž˜์Šค ๋ฏน์Šค์ธ ์ œ์•ˆ ์€ ๊ทธ ๊ฒฝ์šฐ์— ์ข‹์€ ๋Œ€์•ˆ์œผ๋กœ ๋ณด์ž…๋‹ˆ๋‹ค.

ํด๋ž˜์Šค์˜ ๋‚ด๋ถ€๋ฅผ ์ •์˜ํ•  ์ˆ˜ ์žˆ๊ธฐ๋ฅผ ์›ํ•˜๋Š” ๊ฒฝ์šฐ ์ด๋ฅผ ์ˆ˜ํ–‰ํ•˜๋Š” ๊ตฌ์กฐํ™”๋œ ๋ฐฉ๋ฒ•์€ ํด๋ž˜์Šค๋ฅผ ํŒจ์น˜ํ•˜๊ฑฐ๋‚˜ ์ƒˆ ํ•˜์œ„ ํด๋ž˜์Šค๋ฅผ ์ •์˜ํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹™๋‹ˆ๋‹ค. ๋‘ ๊ฐ€์ง€ ๋ชจ๋‘ TypeScript๊ฐ€ ํด๋ž˜์Šค ์ปจํ…์ŠคํŠธ์—์„œ ์ถ”๋ก ํ•˜๋Š” ๋ฐ ์–ด๋ ค์›€์„ ๊ฒช์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค ํ•˜์ง€๋งŒ ํด๋ž˜์Šค ์ž์ฒด์—์„œ ์ •์˜ํ•˜๊ฑฐ๋‚˜ TypeScript๊ฐ€ ์ถ”๋ก ํ•  ์ˆ˜ ์žˆ๋Š” ํ•„์š”ํ•œ ์†์„ฑ์ด ์žˆ๋Š” ์ƒˆ ์Šˆํผํด๋ž˜์Šค๋ฅผ ๋งŒ๋“œ๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋Š” ํด๋ž˜์Šค๋‚˜ ๋Œ€๋ถ€๋ถ„์˜ ์†Œ๋น„์ž๊ฐ€ ๋ณผ ์ˆ˜ ์žˆ๋Š” ๋ฐฉ์‹์œผ๋กœ ํด๋ž˜์Šค์˜ ๋ชจ์–‘์„ ๋ณ€๊ฒฝํ•ด์„œ๋Š” ์•ˆ ๋ฉ๋‹ˆ๋‹ค. @masaeedu ๋ฐ”๋กœ ์—ฌ๊ธฐ์ž…๋‹ˆ๋‹ค.

๋‹น์‹ ์ด ๋งํ•˜๋Š” ๊ฒƒ์ด ์‚ฌ์‹ค์ด์ง€๋งŒ TypeScript๋Š” ๊นจ๋—ํ•œ ์ฝ”๋”ฉ ๊ด€ํ–‰์„ ์‹œํ–‰ํ•˜๊ธฐ ์œ„ํ•ด ์กด์žฌํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ JavaScript ์ฝ”๋“œ๋ฅผ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์ž…๋ ฅํ•˜๊ธฐ ์œ„ํ•ด ์กด์žฌํ•˜๋ฉฐ ์ด ๊ฒฝ์šฐ ์‹คํŒจํ•ฉ๋‹ˆ๋‹ค.

@masaeedu @zajrik์ด ๋งํ•œ ๊ฒƒ. ํด๋ž˜์Šค์— ์†์„ฑ์„ ์ถ”๊ฐ€ํ•œ ๋‹ค์Œ ํด๋ž˜์Šค์—์„œ ์‚ฌ์šฉ๋˜๋Š” "์˜จ๋ผ์ธ ์„œ๋น„์Šค"๋ฅผ ์„ ์–ธํ•˜๋Š” ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ๊ฐ€ ๋ˆ„๋ฝ๋˜๊ณ  ์ œ์•ฝ ์กฐ๊ฑด์ด ์ ์šฉ๋˜๊ธฐ ๋•Œ๋ฌธ์— ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์„œ๋ธŒํด๋ž˜์‹ฑํ•˜๊ฑฐ๋‚˜ ๊ตฌํ˜„ํ•˜๋Š” ๊ฒƒ์€ ์˜ต์…˜์ด ์•„๋‹™๋‹ˆ๋‹ค(์ฝ”๋“œ ์ค‘๋ณต์„ ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•ด ๋…ธ๋ ฅํ•˜๋Š” ๊ฒฝ์šฐ).

@TomMarius ๋‚ด ์š”์ ์€ ์˜ฌ๋ฐ”๋ฅธ ์œ ํ˜• ๊ฒ€์‚ฌ๋ผ๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ํด๋ž˜์Šค์— ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ ๊ธฐ๋Šฅ์„ ์ ์šฉํ•˜๋ฉด ํด๋ž˜์Šค๊ฐ€ ๋ณ€๊ฒฝ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ƒˆ ํด๋ž˜์Šค๋Š” ์›๋ž˜ ํด๋ž˜์Šค์˜ ์ผ๋ถ€ ๋ณ€ํ™˜์„ ํ†ตํ•ด ์ƒ์„ฑ๋˜๋ฉฐ ์ด ์ƒˆ ํด๋ž˜์Šค๋งŒ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ ๊ธฐ๋Šฅ์— ์˜ํ•ด ๋„์ž…๋œ API๋ฅผ ์ง€์›ํ•˜๋„๋ก ๋ณด์žฅ๋ฉ๋‹ˆ๋‹ค.

"๋ฉ”ํƒ€๋ฐ์ดํ„ฐ ๋ˆ„๋ฝ ๋ฐ ์ œ์•ฝ ์กฐ๊ฑด ์ ์šฉ"์ด ๋ฌด์—‡์„ ์˜๋ฏธํ•˜๋Š”์ง€ ๋ชจ๋ฅด์ง€๋งŒ(๊ตฌ์ฒด์ ์ธ ์˜ˆ๊ฐ€ ๋„์›€์ด ๋  ์ˆ˜ ์žˆ์Œ) ํด๋ž˜์Šค๊ฐ€ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๊ฐ€ ๋„์ž…ํ•œ API์— ๋ช…์‹œ์ ์œผ๋กœ ์˜์กดํ•˜๋Š” ๊ฒฝ์šฐ @justinfagnani ๊ฐ€ ๋ณด์—ฌ์ค€ ๋ฏน์Šค์ธ ํŒจํ„ด์„ ํ†ตํ•ด ์ง์ ‘ ํ•˜์œ„ ํด๋ž˜์Šคํ™”ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. , ๋˜๋Š” ์ƒ์„ฑ์ž ๋“ฑ์„ ํ†ตํ•ด ์ฃผ์ž…ํ•˜์‹ญ์‹œ์˜ค. ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ์˜ ์œ ์šฉ์„ฑ์€ ์ˆ˜์ • ์ด ๊ธˆ์ง€๋œ ํด๋ž˜์Šค๊ฐ€ ํ•ด๋‹น ํด๋ž˜์Šค๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์ฝ”๋“œ ์˜ ์ด์ ์„ ์œ„ํ•ด ํ™•์žฅ๋  ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ํด๋ž˜์Šค๋ฅผ ์ง์ ‘ ์ •์˜ํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒฝ์šฐ extends ๋ฅผ ์‚ฌ์šฉํ•˜์‹ญ์‹œ์˜ค.

@masaeedu ์–ด๋–ค ์ข…๋ฅ˜์˜ RPC ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ๊ฐœ๋ฐœ ์ค‘์ด๊ณ  ์‚ฌ์šฉ์ž๊ฐ€ ๋น„๋™๊ธฐ์‹ ๋ฉ”์„œ๋“œ๋งŒ ์ž‘์„ฑํ•˜๋„๋ก ํ•˜๋ ค๋Š” ๊ฒฝ์šฐ ์ƒ์† ๊ธฐ๋ฐ˜ ์ ‘๊ทผ ๋ฐฉ์‹์„ ์‚ฌ์šฉํ•˜๋ฉด ์ฝ”๋“œ๋ฅผ ๋ณต์ œํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค(๋˜๋Š” ์˜ฌ๋ฐ”๋ฅธ ๋ฐฉ๋ฒ•์„ ์ฐพ์ง€ ๋ชปํ–ˆ์Šต๋‹ˆ๋‹ค). , ์•„๋งˆ๋„ - ๋ฐฉ๋ฒ•์„ ์•Œ๊ณ  ์žˆ๋‹ค๋ฉด ์•Œ๋ ค์ฃผ์‹œ๋ฉด ๊ธฐ์  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์ƒ์† ๊ธฐ๋ฐ˜ ์ ‘๊ทผ ๋ฐฉ์‹
์ •์˜: export abstract class Service<T extends { [P in keyof T]: () => Promise<IResult>}> { protected someMethod(): Promise<void> { return Promise.reject(""); } }
์‚ฌ์šฉ๋ฒ•: export default class MyService extends Service<MyService> { async foo() { return this.someMethod(); } }

๋ฐ์ฝ”๋ ˆ์ดํ„ฐ ๊ธฐ๋ฐ˜ ์ ‘๊ทผ ๋ฐฉ์‹
์ •์˜: export function service<T>(target: { new (): T & { [P in keyof T]: () => Promise<IResult> } }) { target.someMethod = function () { return Promise.reject(""); }; return target; }
์‚ฌ์šฉ๋ฒ•: <strong i="17">@service</strong> export default class { async foo() { return this.someMethod(); } }

์ƒ์† ๊ธฐ๋ฐ˜ ์ ‘๊ทผ ์˜ˆ์ œ์—์„œ ์ฝ”๋“œ ์ค‘๋ณต์„ ๋ช…ํ™•ํ•˜๊ฒŒ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ €์™€ ์ œ ์‚ฌ์šฉ์ž๋Š” ํด๋ž˜์Šค๋ฅผ ๋ณต์‚ฌํ•˜์—ฌ ๋ถ™์—ฌ๋„ฃ๊ฑฐ๋‚˜ "any"๋ฅผ ์œ ํ˜• ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ์‚ฌ์šฉํ•˜๊ธฐ ์‹œ์ž‘ํ–ˆ์„ ๋•Œ ์œ ํ˜• ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ๋ณ€๊ฒฝํ•˜๋Š” ๊ฒƒ์„ ์žŠ์–ด๋ฒ„๋ฆฌ๊ณ  ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๊ฐ€ ์ž‘๋™์„ ๋ฉˆ์ถ˜ ์ ์ด ์—ฌ๋Ÿฌ ๋ฒˆ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค. ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ ๊ธฐ๋ฐ˜ ์ ‘๊ทผ ๋ฐฉ์‹์€ ๊ฐœ๋ฐœ์ž์—๊ฒŒ ํ›จ์”ฌ ๋” ์นœ์ˆ™ํ•ฉ๋‹ˆ๋‹ค.

๊ทธ ํ›„ ์ƒ์† ๊ธฐ๋ฐ˜ ์ ‘๊ทผ ๋ฐฉ์‹์—๋Š” ๋˜ ๋‹ค๋ฅธ ๋ฌธ์ œ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด์ œ ๋ฆฌํ”Œ๋ ‰์…˜ ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ๊ฐ€ ๋ˆ„๋ฝ๋˜์–ด service ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋ฅผ ๋„์ž…ํ•ด์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ฝ”๋“œ๋ฅผ ํ›จ์”ฌ ๋” ๋ณต์ œํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์‚ฌ์šฉ๋ฒ•์€ ํ˜„์žฌ <strong i="22">@service</strong> export default class MyService extends Service<MyService> { async foo() { return this.someMethod(); } } ์ด๋ฉฐ ์•ฝ๊ฐ„์˜ ๋ถˆํŽธํ•จ์ด ์•„๋‹ˆ๋ผ ๊ทธ์ € ๋น„์šฐํ˜ธ์ ์ž…๋‹ˆ๋‹ค.

์˜๋ฏธ์ƒ์œผ๋กœ ํด๋ž˜์Šค๊ฐ€ ์ •์˜๋œ ํ›„์— ์ˆ˜์ •์ด ์ˆ˜ํ–‰๋˜๋Š” ๊ฒƒ์ด ์‚ฌ์‹ค์ด์ง€๋งŒ ์žฅ์‹๋˜์ง€ ์•Š์€ ํด๋ž˜์Šค๋ฅผ ์ธ์Šคํ„ด์Šคํ™”ํ•  ๋ฐฉ๋ฒ•์ด ์—†์œผ๋ฏ€๋กœ ๋•Œ๋•Œ๋กœ ๋ถ€์ •ํ™•ํ•œ ์ฝ”๋“œ๋ฅผ ํ—ˆ์šฉํ•˜๋Š” ๊ฒƒ ์™ธ์—๋Š” ํด๋ž˜์Šค์˜ ๋ณ€ํ˜•์„ ์ ์ ˆํ•˜๊ฒŒ ์ง€์›ํ•˜์ง€ ์•Š์„ ์ด์œ ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค(๊ทธ๋Ÿฌ๋‚˜ ๋•Œ๋กœ๋Š” ๋” ๋‚˜์€ ์„ ์„ ์œ„ํ•ด). JavaScript๋Š” ์—ฌ์ „ํžˆ ํ”„๋กœํ† ํƒ€์ž…์— ๊ธฐ๋ฐ˜ํ•˜๊ณ  ์žˆ์œผ๋ฉฐ ํด๋ž˜์Šค ๊ตฌ๋ฌธ์€ ์ด๋ฅผ ๋ฎ๊ธฐ ์œ„ํ•œ ์„คํƒ•์ผ ๋ฟ์ž…๋‹ˆ๋‹ค. ํ”„๋กœํ† ํƒ€์ž…์€ ๋ณ€๊ฒฝ ๊ฐ€๋Šฅํ•˜๊ณ  ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ์— ์˜ํ•ด ์Œ์†Œ๊ฑฐ๋  ์ˆ˜ ์žˆ์œผ๋ฉฐ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์ž…๋ ฅํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

ํด๋ž˜์Šค์— ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ ๊ธฐ๋Šฅ์„ ์ ์šฉํ•˜๋ฉด ํด๋ž˜์Šค๊ฐ€ ๋ณ€๊ฒฝ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์‚ฌ์‹ค์ด ์•„๋‹™๋‹ˆ๋‹ค. ํด๋ž˜์Šค์— ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ ๊ธฐ๋Šฅ์„ ์ ์šฉํ•˜๋ฉด ์–ด๋–ค ์‹์œผ๋กœ๋“  ํด๋ž˜์Šค๊ฐ€ ๋ณ€๊ฒฝ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋‹น์‹ ์ด ๊ทธ๊ฒƒ์„ ์ข‹์•„ํ•˜๋“  ๊ทธ๋ ‡์ง€ ์•Š๋“ .

@TomMarius ๋‹น์‹ ์€ ์—ฌ๊ธฐ์—์žˆ๋Š” ์ฃผ์žฅ๊ณผ ์™„์ „ํžˆ ๊ด€๋ จ์ด์—†๋Š” ์ผ๋ถ€ ๊ณ„์•ฝ์„ ์‹œํ–‰ํ•˜๊ธฐ ์œ„ํ•ด ์ถ”๋ก ์„ ์ด์šฉํ•˜๋ ค๊ณ ํ•ฉ๋‹ˆ๋‹ค. ๋‹ค์Œ์„ ์ˆ˜ํ–‰ํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.

function service<T>(target: { new (): T & {[P in keyof T]: () => Promise<any> } }) { return target };

// Does not type check
const MyWrongService = service(class {
    foo() { return ""; }
})

// Type checks
const MyRightService = service(class {
    async foo() { return ""; }
})

ํด๋ž˜์Šค ๋‚ด๋ถ€๊ฐ€ ๋ฐ์ฝ”๋ ˆ์ดํŒ… ๊ธฐ๋Šฅ์„ ์ธ์‹ํ•  ํ•„์š”๋Š” ์ „ํ˜€ ์—†์Šต๋‹ˆ๋‹ค.

@masaeedu ๊ทธ๊ฒƒ์€ ๋‚ด ์š”์ ์ด ์•„๋‹ˆ ์—ˆ์Šต๋‹ˆ๋‹ค. ์„œ๋น„์Šค ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ/์„œ๋น„์Šค ํด๋ž˜์Šค๋Š” ๋ช‡ ๊ฐ€์ง€ ์ƒˆ๋กœ์šด ์†์„ฑ์„ ๋„์ž…ํ–ˆ์œผ๋ฉฐ ์ด๋Ÿฌํ•œ ์†์„ฑ์€ ์‚ฌ์šฉํ•  ํด๋ž˜์Šค์—์„œ ํ•ญ์ƒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์ง€๋งŒ ์œ ํ˜• ์‹œ์Šคํ…œ์€ ์ด๋ฅผ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ๋ฐ˜์˜ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋‹น์‹ ์€ ๋‚ด๊ฐ€ ๊ทธ๊ฒƒ์„ ์œ„ํ•ด ์ƒ์†์„ ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค๊ณ  ๋งํ–ˆ๊ณ , ๊ทธ๋ž˜์„œ ๋‚ด๊ฐ€ ์™œ ๋‚ด๊ฐ€ ํ•  ์ˆ˜ ์—†๊ฑฐ๋‚˜ ์›ํ•˜์ง€ ์•Š๋Š”์ง€ ๋ณด์—ฌ์ฃผ์—ˆ์Šต๋‹ˆ๋‹ค.

๋” ๋ช…ํ™•ํ•˜๊ฒŒ ์˜ˆ์ œ๋ฅผ ํŽธ์ง‘ํ–ˆ์Šต๋‹ˆ๋‹ค.

@masaeedu ๊ทธ๊ฑด ๊ทธ๋ ‡๊ณ , "๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋Š” ์›๋ž˜ ํด๋ž˜์Šค์—์„œ ์ƒˆ ํด๋ž˜์Šค๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค"๋ผ๋Š” ๋ฌธ์žฅ์€ ์˜ฌ๋ฐ”๋ฅด์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์„œ ์šฐ๋ฆฌ๊ฐ€ ๋ชจ๋‘ ๋ณด์—ฌ์ค€ ๋ชจ๋“  ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋Š” ๋ณ€ํ˜•๋˜๊ฑฐ๋‚˜ ์ง์ ‘ ์›๋ž˜ ํด๋ž˜์Šค๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋ฉฐ ๊ฒฐ์ฝ” ์ƒˆ๋กœ์šด ํด๋ž˜์Šค๋ฅผ ๋ฐ˜ํ™˜ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

@TomMarius ๊ท€ํ•˜์˜ ์˜๊ฒฌ์€ "์‚ฌ์šฉ์ž๊ฐ€ ๋น„๋™๊ธฐ์‹ ๋ฉ”์„œ๋“œ๋งŒ ์ž‘์„ฑํ•˜๋„๋ก ๊ฐ•์ œํ•˜๋Š”" ๋ฌธ์ œ์— ๋Œ€ํ•ด ์–ธ๊ธ‰ํ–ˆ๋Š”๋ฐ, ์ด๋Š” ์ œ ์˜๊ฒฌ์—์„œ ํ•ด๊ฒฐํ•˜๋ ค๊ณ  ํ–ˆ๋˜ ๋ฌธ์ œ์ž…๋‹ˆ๋‹ค. ์‚ฌ์šฉ์ž๊ฐ€ ์˜ˆ์ƒํ•˜๋Š” ๊ณ„์•ฝ์„ ๋”ฐ๋ž๋Š”์ง€ ๊ฐ•์ œํ•˜๋Š” ๊ฒƒ์€ ์‚ฌ์šฉ์ž์˜ ์ฝ”๋“œ๊ฐ€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋กœ ๋‹ค์‹œ ์ „๋‹ฌ๋  ๋•Œ๋งˆ๋‹ค ์ˆ˜ํ–‰๋˜์–ด์•ผ ํ•˜๋ฉฐ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๊ฐ€ ํด๋ž˜์Šค ๋‚ด๋ถ€์— ์ œ๊ณต๋œ ์œ ํ˜• ๋ชจ์–‘์„ ๋ณ€๊ฒฝํ•ด์•ผ ํ•˜๋Š”์ง€ ์—ฌ๋ถ€์— ๋Œ€ํ•œ ๋…ผ์˜์™€ ์•„๋ฌด ๊ด€๋ จ์ด ์—†์Šต๋‹ˆ๋‹ค. ์‚ฌ์šฉ์ž ์ฝ”๋“œ์— API๋ฅผ ์ œ๊ณตํ•˜๋Š” ์ง๊ต ๋ฌธ์ œ๋Š” ํ‘œ์ค€ ์ƒ์† ๋˜๋Š” ๊ตฌ์„ฑ ์ ‘๊ทผ ๋ฐฉ์‹์œผ๋กœ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

@ohjames ๋‹จ์ˆœํžˆ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋ฅผ ์ ์šฉํ•œ๋‹ค๊ณ  ํ•ด์„œ ํด๋ž˜์Šค๊ฐ€ ๋ฐ”๋€Œ๋Š” ๊ฒƒ์€ ์•„๋‹™๋‹ˆ๋‹ค. JS๋Š” ์ˆœ๋„๋ฅผ ๊ฐ•์š”ํ•˜์ง€ ์•Š์œผ๋ฏ€๋กœ ๋ถ„๋ช…ํžˆ ์ฝ”๋“œ์˜ ๋ชจ๋“  ๋ช…๋ น๋ฌธ์ด ๋‹ค๋ฅธ ๊ฒƒ์„ ์ˆ˜์ •ํ•  ์ˆ˜ ์žˆ์ง€๋งŒ ์ด๊ฒƒ์€ ์ด ๊ธฐ๋Šฅ ๋…ผ์˜์™€ ๊ด€๋ จ์ด ์—†์Šต๋‹ˆ๋‹ค. ๊ธฐ๋Šฅ์ด ๊ตฌํ˜„๋œ ํ›„์—๋„ TypeScript๋Š” ํ•จ์ˆ˜ ๋ณธ๋ฌธ ๋‚ด์—์„œ ์ž„์˜์˜ ๊ตฌ์กฐ์  ๋ณ€๊ฒฝ ์‚ฌํ•ญ์„ ์ถ”์ ํ•˜๋Š” ๋ฐ ๋„์›€์ด ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

@masaeedu ๋‹น์‹ ์€ ๋น„ํŠธ๋ฅผ ๊ณ ๋ฅด๊ณ  ์žˆ์ง€๋งŒ ํฐ ๊ทธ๋ฆผ์„ ๋งํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ด ์Šค๋ ˆ๋“œ์— ์žˆ๋Š” ๋‚ด ๋ชจ๋“  ์˜๊ฒฌ์„ ๊ฒ€ํ† ํ•˜์‹ญ์‹œ์˜ค. ์š”์ ์€ ๊ฐœ๋ณ„ ๋ฌธ์ œ๊ฐ€ ์•„๋‹ˆ๋ผ ๋™์‹œ์— ๋ฐœ์ƒํ•˜๋Š” ๊ฐ ๋ฌธ์ œ์— ์žˆ์Šต๋‹ˆ๋‹ค. ๋‚˜๋Š” ์ƒ์† ๊ธฐ๋ฐ˜ ์ ‘๊ทผ ๋ฐฉ์‹์˜ ๋ฌธ์ œ๋ฅผ ์ž˜ ์„ค๋ช…ํ–ˆ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ๋งŽ์€ ์ฝ”๋“œ ์ค‘๋ณต์ด ์žˆ์Šต๋‹ˆ๋‹ค.

๋ช…ํ™•์„ฑ์„ ์œ„ํ•ด ์ด๊ฒƒ์€ ๋‚˜์—๊ฒŒ "๊นจ๋—ํ•œ ์ฝ”๋“œ"์— ๊ด€ํ•œ ๊ฒƒ์ด ์•„๋‹™๋‹ˆ๋‹ค. ๋ฌธ์ œ๋Š” ์‹ค์šฉ์„ฑ์ž…๋‹ˆ๋‹ค. @foo ๋ฅผ ํ•จ์ˆ˜ ์‘์šฉ ํ”„๋กœ๊ทธ๋žจ๊ณผ ๋™์ผํ•˜๊ฒŒ ์ทจ๊ธ‰ํ•˜๋ฉด ์œ ํ˜• ์‹œ์Šคํ…œ์„ ํฌ๊ฒŒ ๋ณ€๊ฒฝํ•  ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. ๋ฐ˜ํ™˜ ์œ ํ˜• ์—์„œ ํ•จ์ˆ˜์˜ ์ธ์ˆ˜ ์— ์œ ํ˜• ์ •๋ณด๋ฅผ ๋„์ž…ํ•˜๋ ค๊ณ  ์‹œ๋„ํ•˜๋Š” ์›œ์˜ ๊นกํ†ต์„ ์—ด๋ฉด ๋™์‹œ์— ์œ ํ˜• ์ถ”๋ก  ๋ฐ TypeScript ์œ ํ˜• ์‹œ์Šคํ…œ์˜ ์—ฌ๋Ÿฌ ๊ตฌ์„์—์„œ ๋ฐœ๊ฒฌ๋˜๋Š” ๋‹ค๋ฅธ ๋ชจ๋“  ๋งˆ๋ฒ•์˜ ์ง์Šน๊ณผ ์ƒํ˜ธ ์ž‘์šฉํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ ๊ณผ๋ถ€ํ•˜๊ฐ€ ์ง€๊ธˆ๊ณผ ๊ฐ™์€ ๋ฐฉ์‹์œผ๋กœ ์ƒˆ๋กœ์šด ๊ธฐ๋Šฅ์— ๋Œ€ํ•œ ํฐ ์žฅ์• ๋ฌผ์ด ๋  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

@TomMarius ์ด ์Šค๋ ˆ๋“œ์˜ ์ฒซ ๋ฒˆ์งธ ์˜๊ฒฌ์€ ๊ด€๋ จ์ด ์—†๋Š” ๊นจ๋—ํ•œ ์ฝ”๋“œ์— ๊ด€ํ•œ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋‹ค์Œ ์ฃผ์„์€ ์˜ˆ์ œ ์ฝ”๋“œ๋ฅผ ์ œ๊ณตํ•œ ์ด ์˜จ๋ผ์ธ ์„œ๋น„์Šค ๊ฐœ๋…์— ๋Œ€ํ•œ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ฒซ ๋ฒˆ์งธ ๋‹จ๋ฝ๋ถ€ํ„ฐ ๋„ค ๋ฒˆ์งธ ๋‹จ๋ฝ๊นŒ์ง€ ์ฃผ์š” ๋ถˆ๋งŒ์€ MyService extends Service<MyService> ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋ฐ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•˜๊ธฐ ์‰ฝ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋‚˜๋Š” ๋‹น์‹ ์ด ์ด๊ฒƒ์„ ์–ด๋–ป๊ฒŒ ๋‹ค๋ฃฐ ์ˆ˜ ์žˆ๋Š”์ง€์— ๋Œ€ํ•œ ์˜ˆ๋ฅผ ๋ณด์—ฌ์ฃผ๋ ค๊ณ  ๋…ธ๋ ฅํ–ˆ์Šต๋‹ˆ๋‹ค.

๋‚˜๋Š” ๊ทธ๊ฒƒ์„ ๋‹ค์‹œ ๋ณด์•˜๊ณ  ๋ฐ์ฝ”๋ ˆ์ดํŒ…๋œ ํด๋ž˜์Šค์˜ ๋ฉค๋ฒ„๊ฐ€ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋ฅผ ์•Œ์•„์•ผ ํ•˜๋Š” ์ด์œ ๋ฅผ ์„ค๋ช…ํ•˜๋Š” ๊ทธ ์˜ˆ์—์„œ ์•„๋ฌด๊ฒƒ๋„ ๋ณผ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ํ‘œ์ค€ ์ƒ์†์œผ๋กœ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์—†๋Š” ์‚ฌ์šฉ์ž์—๊ฒŒ ์ œ๊ณตํ•˜๋Š” ์ด๋Ÿฌํ•œ ์ƒˆ ์†์„ฑ์€ ๋ฌด์—‡์ž…๋‹ˆ๊นŒ? ๋‚˜๋Š” ๋ฐ˜์„ฑ์œผ๋กœ ์ž‘์—…ํ•˜์ง€ ์•Š์•˜๊ธฐ ๋•Œ๋ฌธ์— ๊ทธ๊ฒƒ์— ๋Œ€ํ•ด ๋Œ€์ถฉ ํ›‘์–ด๋ณธ ์ ์ด ์žˆ์Šต๋‹ˆ๋‹ค. ์ฃ„์†กํ•ฉ๋‹ˆ๋‹ค.

@masaeedu ๋‚˜๋Š” ์ƒ์†์œผ๋กœ ๊ทธ๊ฒƒ์„ ๋‹ฌ์„ฑํ•  ์ˆ˜ ์žˆ์ง€๋งŒ ์ƒ์†์œผ๋กœ ์ธํ•ด ๋‚˜/๋‚ด ์‚ฌ์šฉ์ž๊ฐ€ ์ฝ”๋“œ๋ฅผ ๋Œ€๋Ÿ‰์œผ๋กœ ๋ณต์ œํ•ด์•ผ ํ•˜๋ฏ€๋กœ ๋‹ค๋ฅธ ๋ฐฉ๋ฒ•์„ ์›ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์ €๋Š” ํ•˜์ง€๋งŒ ์œ ํ˜• ์‹œ์Šคํ…œ์ด ํ˜„์‹ค์„ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ๋ฐ˜์˜ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

์š”์ ์€ service ๊ฐ€ <T>(target: T) => T & IService ๋กœ ์„ ์–ธ๋œ ์˜ฌ๋ฐ”๋ฅธ ์œ ํ˜•์˜ <strong i="7">@service</strong> class X { } ๊ฐ€ X ๊ฐ€ ์•„๋‹ˆ๋ผ X & IService ; ๋ฌธ์ œ๋Š” ์‹ค์ œ๋กœ๋Š” ํด๋ž˜์Šค ๋‚ด๋ถ€์—์„œ๋„ ์‚ฌ์‹ค์ด๋ผ๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์˜๋ฏธ์ƒ ์‚ฌ์‹ค์ด ์•„๋‹์ง€๋ผ๋„ ๋ง์ž…๋‹ˆ๋‹ค.

์ด ๋ฌธ์ œ๊ฐ€ ์•ผ๊ธฐํ•˜๋Š” ๋˜ ๋‹ค๋ฅธ ํฐ ๊ณ ํ†ต์€ ๊ฐ๊ฐ ์ œ์•ฝ์ด ์žˆ๋Š” ์ผ๋ จ์˜ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๊ฐ€ ์žˆ์„ ๋•Œ ์œ ํ˜• ์‹œ์Šคํ…œ์ด ๋Œ€์ƒ์ด ์žฅ์‹๋œ ํด๋ž˜์Šค๊ฐ€ ์•„๋‹ˆ๋ผ ํ•ญ์ƒ ์›๋ž˜ ํด๋ž˜์Šค๋ผ๊ณ  ์ƒ๊ฐํ•˜๋ฏ€๋กœ ์ œ์•ฝ ์กฐ๊ฑด์ด ์“ธ๋ชจ๊ฐ€ ์—†๋‹ค๊ณ  ์ƒ๊ฐํ•œ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์ƒ์†์œผ๋กœ ๋‹ฌ์„ฑํ•  ์ˆ˜ ์žˆ์ง€๋งŒ ์ƒ์†์œผ๋กœ ์ธํ•ด ๋‚˜/๋‚ด ์‚ฌ์šฉ์ž๊ฐ€ ์ฝ”๋“œ๋ฅผ ๋Œ€๋Ÿ‰์œผ๋กœ ๋ณต์ œํ•ด์•ผ ํ•˜๋ฏ€๋กœ ๋‹ค๋ฅธ ๋ฐฉ๋ฒ•์„ ์‚ฌ์šฉํ•˜๊ณ  ์‹ถ์Šต๋‹ˆ๋‹ค.

์ดํ•ด๊ฐ€ ์•ˆ๋˜๋Š” ๋ถ€๋ถ„์ž…๋‹ˆ๋‹ค. ์‚ฌ์šฉ์ž๋Š” IService ๋ฅผ ๊ตฌํ˜„ํ•ด์•ผ ํ•˜๊ณ  TheirService implements IService ๊ฐ€ ๋‹ค๋ฅธ ๊ณ„์•ฝ { [P in keyof blablablah] } $ ๋„ ์ค€์ˆ˜ํ•˜๋Š”์ง€ ํ™•์ธํ•˜๊ณ  ์•„๋งˆ๋„ { potato: Potato } ๊ทธ๋“ค์˜ ์„œ๋น„์Šค์—. ์ด ๋ชจ๋“  ๊ฒƒ์€ ํด๋ž˜์Šค ๋ฉค๋ฒ„๊ฐ€ @service ๋ฅผ ์ธ์‹ํ•˜์ง€ ์•Š๊ณ ๋„ ์‰ฝ๊ฒŒ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

import { serviceDecorator, BaseService } from 'library';

// Right now
const MyService = serviceDecorator(class extends BaseService {
    async foo(): { return ""; }
})

const MyBrokenService1 = serviceDecorator(class extends BaseService {
    foo(): { return; } // Whoops, forgot async! Not assignable
});

const MyBrokenService2 = serviceDecorator(class { // Whoops, forgot to extend BaseService! Not assignable
    async foo(): { return; } 
});

// Once #4881 lands
<strong i="13">@serviceDecorator</strong>
class MyService extends BaseService {
    async foo(): { return ""; }
}

๋‘ ๊ฒฝ์šฐ ๋ชจ๋‘ serviceDecorator this ~ foo ์˜ ์œ ํ˜•์œผ๋กœ ์ œ์‹œํ•ด์•ผ๋งŒ ๋‹ฌ์„ฑํ•  ์ˆ˜ ์žˆ๋Š” ๊ฐ„๊ฒฐํ•จ์˜ ๊ฑฐ๋Œ€ํ•œ ์Šน๋ฆฌ๋Š” ์—†์Šต๋‹ˆ๋‹ค. ๋” ์ค‘์š”ํ•œ ๊ฒƒ์€, ์ด๋ฅผ ์œ„ํ•œ ๊ท ์ผํ•œ ํƒ€์ดํ•‘ ์ „๋žต์„ ์ œ์•ˆํ•˜๋Š” ๋ฐฉ๋ฒ•์€ ๋ฌด์—‡์ž…๋‹ˆ๊นŒ? serviceDecorator ์˜ ๋ฐ˜ํ™˜ ์œ ํ˜•์€ ์žฅ์‹ํ•˜๋Š” ํด๋ž˜์Šค์˜ ์œ ํ˜•์„ ๊ธฐ๋ฐ˜์œผ๋กœ ์œ ์ถ”๋˜๋ฉฐ, ์ด์ œ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ์˜ ๋ฐ˜ํ™˜ ์œ ํ˜•์œผ๋กœ ์ž…๋ ฅ๋ฉ๋‹ˆ๋‹ค.

์•ˆ๋…•ํ•˜์„ธ์š” @masaeedu , ๊ฐ„๊ฒฐํ•จ์€ ๋‘˜ ์ด์ƒ์ผ ๋•Œ ํŠนํžˆ ๊ฐ€์น˜๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

@Component({ /** component args **/})
@Authorized({/** roles **/)
<strong i="7">@HasUndoContext</strong>
class MyComponent  {
  // do stuff with undo context, component methods etc
}

๊ทธ๋Ÿฌ๋‚˜ ์ด ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•์€ ํด๋ž˜์Šค ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ์˜ ๋Œ€์•ˆ์ผ ๋ฟ์ž…๋‹ˆ๋‹ค. ๋ฉ”์„œ๋“œ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ์˜ ๊ฒฝ์šฐ ํ˜„์žฌ ์†”๋ฃจ์…˜์ด ์—†์œผ๋ฉฐ ๋ฉ‹์ง„ ๊ตฌํ˜„์ด ๋„ˆ๋ฌด ๋งŽ์ด ์ฐจ๋‹จ๋ฉ๋‹ˆ๋‹ค. ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋Š” 2๋‹จ๊ณ„์—์„œ ์ œ์•ˆ ์ค‘์ž…๋‹ˆ๋‹ค - https://github.com/tc39/proposal-decorators . ๊ทธ๋Ÿฌ๋‚˜ ๊ตฌํ˜„์ด ํ›จ์”ฌ ๋” ์ผ์ฐ ์ด๋ฃจ์–ด์ง„ ๊ฒฝ์šฐ๊ฐ€ ๋งŽ์Šต๋‹ˆ๋‹ค. ํŠนํžˆ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋Š” ์ด๋ฏธ ๋งŽ์€ ํ”„๋ ˆ์ž„์›Œํฌ์—์„œ ์‚ฌ์šฉ๋˜์—ˆ๊ณ  ๋งค์šฐ ๊ฐ„๋‹จํ•œ ๋ฒ„์ „์ด ์ด๋ฏธ babel/ts์— ๊ตฌํ˜„๋˜์–ด ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์ •๋ง ์ค‘์š”ํ•œ ์ค‘์š”ํ•œ ๋ฒฝ๋Œ ์ค‘ ํ•˜๋‚˜๋ผ๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ์ด ๋ฌธ์ œ๊ฐ€ ๊ตฌํ˜„๋  ์ˆ˜ ์žˆ๋‹ค๋ฉด ๊ณต์‹ ๋ฆด๋ฆฌ์Šค๊นŒ์ง€ ์‹คํ—˜ ์ƒํƒœ๋ฅผ ์žƒ์ง€ ์•Š์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๊ทธ๊ฒƒ์€ "์‹คํ—˜์ "์ž…๋‹ˆ๋‹ค.

@pietschy ์˜ˆ, @ ๊ตฌ๋ฌธ ์„คํƒ•์ด ์œ ํ˜• ๊ฒ€์‚ฌ์™€ ํ•จ๊ป˜ ์ œ๋Œ€๋กœ ์ž‘๋™ํ•˜๋„๋ก ํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค. ํ˜„์žฌ ํ•จ์ˆ˜ ํ•ฉ์„ฑ์„ ์‚ฌ์šฉํ•˜์—ฌ ํ•ฉ๋ฆฌ์ ์œผ๋กœ ์œ ์‚ฌํ•œ ๊ฐ„๊ฒฐ์„ฑ์„ ์–ป์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

const decorator = compose(
    Component({ /** component args **/ }),
    Authorized({ /** roles **/ })
    HasUndoContext
);

const MyComponent = decorator(class {
});

์•ž์˜ ๋…ผ์˜๋Š” ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ์˜ ๋ฐ˜ํ™˜ ์œ ํ˜•์ด this ์œ ํ˜•์œผ๋กœ ํด๋ž˜์Šค ๋ฉค๋ฒ„์—๊ฒŒ ์ œ๊ณต๋˜๋Š” ์ผ์ข…์˜ ์—ญ ํƒ€์ดํ•‘์„ ์ˆ˜ํ–‰ํ•˜๋Š” ๊ฒƒ์ด ์ข‹์€ ์•„์ด๋””์–ด์ธ์ง€ ์—ฌ๋ถ€์— ๋Œ€ํ•œ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์•ˆ๋…•ํ•˜์„ธ์š” @masaeedu , ๋„ค, ํ† ๋ก ์˜ ๋งฅ๋ฝ์„ ์ดํ•ดํ–ˆ์Šต๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ // do stuff with undo context, component methods etc ์ž…๋‹ˆ๋‹ค. ๊ฑด๋ฐฐ

Mixins๋ฅผ ๋” ์‰ฝ๊ฒŒ ๋งŒ๋“ค์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

typescript(javascript)๋Š” ๋‹ค์ค‘ ์ƒ์†์„ ์ง€์›ํ•˜์ง€ ์•Š์œผ๋ฏ€๋กœ Mixins ๋˜๋Š” Traits๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
๊ทธ๋ฆฌ๊ณ  ์ง€๊ธˆ์€ ํŠนํžˆ ๋‚ด๊ฐ€ ๋ฌด์–ธ๊ฐ€๋ฅผ ์žฌ๊ตฌ์„ฑํ•  ๋•Œ ๋งŽ์€ ์‹œ๊ฐ„์„ ๋‚ญ๋น„ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.
๊ทธ๋ฆฌ๊ณ  ๋ชจ๋“  ๊ณณ์—์„œ "๋นˆ ๊ตฌํ˜„"์ด ์žˆ๋Š” ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๋ณต์‚ฌํ•˜์—ฌ ๋ถ™์—ฌ๋„ฃ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. (#371)

--
๋‚˜๋Š” ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ์˜ ๋ฐ˜ํ™˜ ์œ ํ˜•์ด ์ˆ˜์—…์— ์ œ์‹œ๋˜์–ด์„œ๋Š” ์•ˆ๋œ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.
์™œ๋ƒํ•˜๋ฉด: .... ํ . ์–ด๋–ป๊ฒŒ ์„ค๋ช…ํ•ด์•ผ ํ• ์ง€ ๋ชจ๋ฅด๊ฒ ์–ด, ๋‚ด ์˜์–ด ์‹ค๋ ฅ์ด ํ˜•ํŽธ์—†์–ด์„œ ๋ฏธ์•ˆํ•ด... ( ๐Ÿค” ์•ก์ž ์—†์ด ์‚ฌ์ง„์ด ์กด์žฌํ•  ์ˆ˜ ์žˆ๋‹ˆ? ) ์ด ์ง์—…์€ interface ์ž…๋‹ˆ๋‹ค.

์—ฌ๊ธฐ์— ๋‚ด +1์„ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค! ๋‚˜๋Š” ๊ทธ๊ฒƒ์ด ๊ณง ๋‚˜์˜ค๋Š” ๊ฒƒ์„ ๋ณด๊ณ  ์‹ถ์Šต๋‹ˆ๋‹ค.

@pietschy ํด๋ž˜์Šค๊ฐ€ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ์— ์˜ํ•ด ์ถ”๊ฐ€๋œ ๋ฉค๋ฒ„์— ์ข…์†๋˜๋Š” ๊ฒฝ์šฐ ๊ทธ ๋ฐ˜๋Œ€๊ฐ€ ์•„๋‹ˆ๋ผ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ์˜ ๊ฒฐ๊ณผ๋ฅผ ํ™•์žฅํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๋‹ค์Œ์„ ์ˆ˜ํ–‰ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

const decorator = compose(
    Component({ /** component args **/ }),
    Authorized({ /** roles **/ })
    HasUndoContext
);

class MyComponent extends decorator(class { }) {
    // do stuff with undo context, component methods etc
};

๋Œ€์•ˆ์€ ์œ ํ˜• ์‹œ์Šคํ…œ์ด ์ผ์ข…์˜ ๋ฃจํ”„์—์„œ ์ž‘๋™ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์„œ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ ํ•จ์ˆ˜์˜ ์ธ์ˆ˜๋Š” ๋ฐ˜ํ™˜ ์œ ํ˜•์— ์˜ํ•ด ์ปจํ…์ŠคํŠธ์ ์œผ๋กœ ์œ ํ˜•์ด ์ง€์ •๋˜๊ณ , ๋ฐ˜ํ™˜ ์œ ํ˜•์— ์˜ํ•ด ์ปจํ…์ŠคํŠธ์ ์œผ๋กœ ์œ ํ˜•์ด ์ง€์ •๋˜๋Š” ์ธ์ˆ˜์—์„œ ์ถ”๋ก ๋ฉ๋‹ˆ๋‹ค. ์šฐ๋ฆฌ๋Š” ์—ฌ์ „ํžˆ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. ์ด๊ฒƒ์ด ์–ด๋–ป๊ฒŒ ์ž‘๋™ํ•ด์•ผ ํ•˜๋Š”์ง€์— ๋Œ€ํ•œ ๊ตฌ์ฒด์ ์ธ ์ œ์•ˆ์€ ๋‹จ์ง€ ๊ตฌํ˜„์„ ๊ธฐ๋‹ค๋ฆฌ๋Š” ๊ฒƒ์ด ์•„๋‹™๋‹ˆ๋‹ค.

@masaeedu ์•ˆ๋…•ํ•˜์„ธ์š”. ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋ฅผ ๊ตฌ์„ฑํ•˜๊ณ  ๊ธฐ๋ณธ ํด๋ž˜์Šค์— ์ ์šฉํ•ด์•ผ ํ•˜๋Š” ์ด์œ ๊ฐ€ ๋ฌด์—‡์ธ์ง€ ํ˜ผ๋ž€์Šค๋Ÿฝ์Šต๋‹ˆ๋‹ค. ๋‚ด๊ฐ€ ์ดํ•ดํ•˜๋Š” ํ•œ ํ”„๋กœํ† ํƒ€์ž…์€ ์‚ฌ์šฉ์ž ๋žœ๋“œ ์ฝ”๋“œ๊ฐ€ ์‹คํ–‰๋  ๋•Œ ์ด๋ฏธ ์ˆ˜์ •๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ์˜ˆ

function pressable<T extends {new(...args:any[]):{}}>(constructor:T) {
    return class extends constructor {
        pressMe() {
            console.log('how depressing');
        }
    }
}

<strong i="7">@pressable</strong>
class UserLandClass {
    constructor() {    
        this['pressMe'](); // this method exists, please let me use code completion.
    }
}

console.log(new UserLandClass());

๋”ฐ๋ผ์„œ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ์— ์˜ํ•ด ์ •์˜๋œ ๋ฉ”์„œ๋“œ๊ฐ€ ์ด๋ฏธ ์กด์žฌํ•˜๊ณ  ํ•ฉ๋ฒ•์ ์œผ๋กœ ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒฝ์šฐ typescript๊ฐ€ ์ด๋ฅผ ๋ฐ˜์˜ํ•˜๋ฉด ์ข‹์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•์„ ๋ถ€๊ณผํ•˜์ง€ ์•Š๊ณ  typescript๊ฐ€ ์ด๊ฒƒ์„ ๋ฐ˜์˜ํ•˜๊ธฐ๋ฅผ ์›ํ•ฉ๋‹ˆ๋‹ค. ๋‹ค๋ฅธ ๊ฒฝ์šฐ
๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๊ฐ€ ํ•  ์ˆ˜ ์žˆ๊ณ  ๋ชจ๋ธ๋งํ•  ์ˆ˜ ์—†๋Š” ์ผ์ด๋ผ๋ฉด ์ ์–ด๋„
์‹œ๋‚˜๋ฆฌ์˜ค๋Š” ์–ด๋–ค ํ˜•ํƒœ๋‚˜ ํ˜•ํƒœ๋กœ ์ง€์›๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

์ด ์Šค๋ ˆ๋“œ๋Š” ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ ๊ฐ€ ๋ฌด์—‡์„ ํ•ด์•ผ ํ•˜๋Š”์ง€, ์–ด๋–ป๊ฒŒ ์‚ฌ์šฉํ•ด์•ผ ํ•˜๋Š”์ง€, ์–ด๋–ป๊ฒŒ ์‚ฌ์šฉํ•˜์ง€ ์•Š์•„์•ผ ํ•˜๋Š”์ง€ ๋“ฑ์— ๋Œ€ํ•œ ์˜๊ฒฌ์œผ๋กœ ๊ฐ€๋“ ์ฐจ ์žˆ์Šต๋‹ˆ๋‹ค.

๋ฐ์ฝ”๋ ˆ์ดํ„ฐ ๊ฐ€ ์‹ค์ œ๋กœ ํ•˜๋Š” ์ผ์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

function addMethod(Class) : any {
    return class extends Class {
        hello(){}
    };
}

<strong i="13">@addMethod</strong>
class Foo{
    originalMethod(){}
}

esnext๋ฅผ ํƒ€๊ฒŸํŒ…ํ•˜๋Š” ๊ฒฝ์šฐ

var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
    return c > 3 && r && Object.defineProperty(target, key, r), r;
};

function addMethod(Class) {
    return class extends Class {
        hello() {
        }
    };
}
let Foo = class Foo {
    originalMethod() { }
};
Foo = __decorate([
    addMethod
], Foo);

__decorate ๋Š” ๊ฐ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋ฅผ ์•„๋ž˜์—์„œ ์œ„๋กœ ์ ์šฉํ•˜๊ณ  ๊ฐ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ์—๋Š” ์™„์ „ํžˆ ์ƒˆ๋กœ์šด ํด๋ž˜์Šค๋ฅผ ๋ฐ˜ํ™˜ํ•  ์ˆ˜ ์žˆ๋Š” ์˜ต์…˜์ด ์žˆ์Šต๋‹ˆ๋‹ค.

๋‚˜๋Š” ์œ ํ˜• ์‹œ์Šคํ…œ์ด ์ด๊ฒƒ์„ ์ง€์›ํ•˜๊ณ  ์ธ์ •ํ•˜๋Š” ๊ฒƒ์ด ๋งค์šฐ ๊นŒ๋‹ค๋กœ์šธ ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์„ ์ดํ•ดํ•˜๊ณ , ์ด๊ฒƒ์„ ์ง€์›ํ•˜๋Š” ๋ฐ ๋งค์šฐ ์‹œ๊ฐ„์ด ๊ฑธ๋ฆด ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์„ ์ดํ•ดํ•˜์ง€๋งŒ, ์šฐ๋ฆฌ ๋ชจ๋‘๊ฐ€ ์ด๊ฒƒ์„ ์‹œ์ž‘ํ•œ ์œ„์˜ ์›๋ž˜ ์ฝ”๋“œ ์ƒ˜ํ”Œ์—์„œ ํ˜„์žฌ ๋™์ž‘์— ๋™์˜ํ•˜์ง€ ์•Š์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ? ์Šค๋ ˆ๋“œ, ๋‹จ์ˆœํžˆ ์ž˜๋ชป๋œ ๊ฒƒ์ž…๋‹ˆ๊นŒ?

๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋‚˜ ๋ฏน์Šค์ธ, ๊ธฐ๋Šฅ์  ๊ตฌ์„ฑ ๋“ฑ์— ๋Œ€ํ•œ ๊ฐœ๋ฐœ์ž์˜ ์˜๊ฒฌ์ด ๋ฌด์—‡์ด๋“  ๊ฐ„์— ์ด๊ฒƒ์€ ๊ฝค ๋ถ„๋ช…ํ•œ ๋ฒ„๊ทธ์ธ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.


์ด๊ฒƒ์ด ํ–ฅํ›„ ๋ฆด๋ฆฌ์Šค์˜ ํŒŒ์ดํ”„๋ผ์ธ์— ์žˆ๋Š”์ง€ ์ •์ค‘ํ•˜๊ฒŒ ์—ฌ์ญค๋ด๋„ ๋ ๊นŒ์š”?

TypeScript๋Š” ์ •๋ง ๋†€๋ž๊ณ  ๋งˆ์Œ์— ๋“ญ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์ด๊ฒƒ์€ ๋‹จ์ˆœํžˆ ๋ถ€์„œ์ง„ ๋ช‡ ์•ˆ ๋˜๋Š”(์œ ์ผํ•œ?) ์กฐ๊ฐ ์ค‘ ํ•˜๋‚˜์ธ ๊ฒƒ ๊ฐ™์œผ๋ฉฐ, ์ˆ˜์ •๋˜๊ธฐ๋ฅผ ๊ณ ๋Œ€ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. :)

@arackaf ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ ๊ฐ€ ์‹ค์ œ๋กœ ๋ฌด์—‡์„ ํ•˜๋Š”์ง€ ์ž˜ ์ดํ•ดํ•˜๊ณ  ์žˆ์œผ๋ฉฐ TypeScript๊ฐ€ ์ด๋ฏธ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋ฅผ ์ง€์›ํ•˜๋Š” ์œ ํ˜•์— ๋Œ€ํ•ด ์‹ ๊ฒฝ ์“ฐ์ง€ ์•Š๋Š”๋‹ค๊ณ  ๊ฐ€์ •ํ•ฉ๋‹ˆ๋‹ค. ์ด ๋ฌธ์ œ์˜ ์ „์ฒด ํ† ๋ก ์€ ๋ฐ์ฝ”๋ ˆ์ดํŒ…๋œ ํด๋ž˜์Šค๊ฐ€ ์œ ํ˜• ์‹œ์Šคํ…œ์—์„œ ์–ด๋–ป๊ฒŒ ํ‘œ์‹œ๋˜์–ด์•ผ ํ•˜๋Š”์ง€์— ๋Œ€ํ•œ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๋‚˜๋Š” new Foo().foo ์œ ํ˜• ์˜ค๋ฅ˜๊ฐ€ ๋ฒ„๊ทธ์ด๋ฉฐ ์‰ฝ๊ฒŒ ๊ณ ์น  ์ˆ˜ ์žˆ๋‹ค๋Š” ๋ฐ ๋™์˜ํ•ฉ๋‹ˆ๋‹ค. return this.foo; ์œ ํ˜• ์˜ค๋ฅ˜๊ฐ€ ๋ฒ„๊ทธ๋ผ๋Š” ๋ฐ ๋™์˜ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ด ๋ฌธ์ œ์—์„œ ์•„์ง๊นŒ์ง€ ์•„๋ฌด๋„ ์ง€์ •ํ•˜์ง€ ์•Š์€ ์œ ํ˜• ์‹œ์Šคํ…œ์˜ ๊ธฐ๋Šฅ์„ ์š”์ฒญํ•˜๊ณ  ์žˆ๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. this ์œ ํ˜•์ด ํฌํ•จํ•˜๋Š” ํด๋ž˜์Šค์— ์ ์šฉ๋œ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ์— ์˜ํ•ด ๋ณ€ํ™˜๋˜์–ด์•ผ ํ•˜๋Š” ์ผ๋ถ€ ๋ฉ”์ปค๋‹ˆ์ฆ˜์„ ์—ผ๋‘์— ๋‘” ๊ฒฝ์šฐ ์ด ๋ฉ”์ปค๋‹ˆ์ฆ˜์„ ๋ช…์‹œ์ ์œผ๋กœ ์ œ์•ˆํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค .

๊ฑฐ์˜ ๋ชจ๋“  ๊ฒฝ์šฐ์— ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ์˜ ๋ฐ˜ํ™˜ ์œ ํ˜•์„ ์‚ฌ์šฉํ•˜์—ฌ ๋ณ€ํ™˜์„ ์ œ์•ˆํ•œ ๋ฐ”๋กœ ๊ทธ ์œ ํ˜•์—์„œ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ์˜ ๋ฐ˜ํ™˜ ์œ ํ˜•์ด ์œ ์ถ”๋˜๊ธฐ ๋•Œ๋ฌธ์— ์ด๋Ÿฌํ•œ ๋ฉ”์ปค๋‹ˆ์ฆ˜์€ ์˜ˆ์ƒ๋งŒํผ ๊ฐ„๋‹จํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ addMethod ๊ฐ€ new () => T ์œ ํ˜•์˜ ํด๋ž˜์Šค๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ new() => T & { hello(): void } ๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๊ฒฝ์šฐ T ๊ฐ€ T & { hello(): void } ์—ฌ์•ผ ํ•œ๋‹ค๊ณ  ์ œ์•ˆํ•˜๋Š” ๊ฒƒ์€ ์ด์น˜์— ๋งž์ง€ ์•Š์Šต๋‹ˆ๋‹ค. super.hello ๋ฅผ ์ฐธ์กฐํ•˜๋Š” ๊ฒƒ์ด ์œ ํšจํ•œ๊ฐ€์š”?

์ด๊ฒƒ์€ ๋‚ด๊ฐ€ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ์˜ ๋ณธ๋ฌธ์—์„œ return class extends ClassIWasPassed { ... } ๋ฅผ ์ˆ˜ํ–‰ํ•˜๋Š” ๊ฒƒ์œผ๋กœ ์ œํ•œ๋˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ํŠนํžˆ ์ ์ ˆํ•ฉ๋‹ˆ๋‹ค. ๋‚ด๊ฐ€ ์›ํ•˜๋Š” ๊ฒƒ์€ ๋ฌด์—‡์ด๋“  ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋นผ๊ธฐ ์œ ํ˜•, ๋งคํ•‘๋œ ์œ ํ˜•, ๊ณต์šฉ์ฒด, ๋ชจ๋‘ ๊ณต์ •ํ•œ ๊ฒŒ์ž„์ž…๋‹ˆ๋‹ค. ๋ชจ๋“  ๊ฒฐ๊ณผ ์œ ํ˜•์€ ์ œ์•ˆํ•˜๋Š” ์ด ์ถ”๋ก  ๋ฃจํ”„์™€ ์ž˜ ์ž‘๋™ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๋ฌธ์ œ๋ฅผ ์„ค๋ช…ํ•˜๊ธฐ ์œ„ํ•ด ์ด ์˜ˆ์—์„œ ์–ด๋–ค ์ผ์ด ๋ฐœ์ƒํ•ด์•ผ ํ•˜๋Š”์ง€ ์•Œ๋ ค์ฃผ์‹ญ์‹œ์˜ค.

type Constructor<T> = new (...args: any[]) => T
type Greeter = { hello(): string }

function logger<T extends Constructor<Greeter>>(Class: T) {
    return class {
        hello() {
            console.log(new Class().hello()) // Do I get a type error here? After all, the signature of Class is { hello: () => void }
        } 
    };
}

// Or should I get the error here? Foo does not conform to { hello(): string }
<strong i="22">@logger</strong>
class Foo {
    hello() { return "foo"; }
}

๋ฌธ์ œ๊ฐ€ "์–ด๋ ต๋‹ค"๊ณ  ๊ทธ๋ƒฅ ๋„˜๊ฒจ์ค„ ์ˆ˜๋Š” ์—†์Šต๋‹ˆ๋‹ค. ๋ˆ„๊ตฐ๊ฐ€ ์‹ค์ œ๋กœ ์ด๊ฒƒ์ด ์–ด๋–ป๊ฒŒ ์ž‘๋™ํ•ด์•ผ ํ•˜๋Š”์ง€ ์ œ์•ˆํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

์˜ค๋ฅ˜๊ฐ€ ์•„๋‹™๋‹ˆ๋‹ค. Greeter๋ฅผ ์ค€์ˆ˜ํ•˜๋Š” Logger ํด๋ž˜์Šค๋ฅผ ์ „๋‹ฌํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ Foo๋Š” ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ์— ์˜ํ•ด ์™„์ „ํžˆ ๋‹ค๋ฅธ ๊ฒƒ์œผ๋กœ ๋ณ€ํ˜•๋˜์–ด ๋” ์ด์ƒ Greeter๋ฅผ ํ™•์žฅํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ๋กœ๊ฑฐ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๊ฐ€ Foo๋ฅผ Greeter๋กœ ์ทจ๊ธ‰ํ•˜๋Š” ๊ฒƒ์€ ์œ ํšจํ•ด์•ผ ํ•˜์ง€๋งŒ Foo๋Š” ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ์— ์˜ํ•ด ์™„์ „ํžˆ ๋‹ค๋ฅธ ๊ฒƒ์— ์žฌํ• ๋‹น๋˜๊ธฐ ๋•Œ๋ฌธ์— ๋‹ค๋ฅธ ์‚ฌ๋žŒ์—๊ฒŒ๋Š” ์œ ํšจํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

๋‚˜๋Š” ์ด๊ฒƒ์„ ๊ตฌํ˜„ ํ•˜๋Š” ๊ฒƒ์ด ์ง€๋…ํ•˜๊ฒŒ ์–ด๋ ค์šธ ๊ฒƒ์ด๋ผ๊ณ  ํ™•์‹ ํ•ฉ๋‹ˆ๋‹ค. ์ด ์Šค๋ ˆ๋“œ์˜ ๋งจ ์œ„์— ๋‚˜์—ด๋œ ๊ฒƒ๊ณผ ๊ฐ™์€ ์ผ๋ฐ˜์ ์ธ ๊ฒฝ์šฐ์— ๋Œ€ํ•ด ํ•ฉ๋ฆฌ์ ์ธ ํ•˜์œ„ ์ง‘ํ•ฉ์ด ๊ฐ€๋Šฅํ•œ๊ฐ€์š”?

@์•„๋ผ์นดํ”„

๊ทธ๋Ÿฌ๋‚˜ Foo๋Š” ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ์— ์˜ํ•ด ์™„์ „ํžˆ ๋‹ค๋ฅธ ๊ฒƒ์œผ๋กœ ๋ณ€๊ฒฝ๋ฉ๋‹ˆ๋‹ค.

Foo ๊ฐ€ ๋ฌด์—‡์ธ์ง€์— ๋Œ€ํ•œ ์ •ํ™•ํ•œ ์ •์˜๋Š” ์—†์Šต๋‹ˆ๋‹ค. ์šฐ๋ฆฌ์˜ ์ „์ฒด ๊ฒฝํ•ฉ ํฌ์ธํŠธ๋Š” Foo ์˜ ๋ฉค๋ฒ„๊ฐ€ ์•ก์„ธ์Šคํ•  ์ˆ˜ ์žˆ์–ด์•ผ ํ•˜๋Š”์ง€(๊ทธ๋Ÿฌ๋ฏ€๋กœ ๊ณต๊ฐœ API์˜ ์ผ๋ถ€๋กœ ๋ฐ˜ํ™˜ํ•ด์•ผ ํ•˜๋Š”์ง€) ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๊ฐ€ this ์—์„œ ๋ฉค๋ฒ„๋ฅผ ๋„์ž…ํ–ˆ๋Š”์ง€ ์—ฌ๋ถ€์ž…๋‹ˆ๋‹ค. Foo ๋Š” ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๊ฐ€ ๋ฐ˜ํ™˜ํ•˜๋Š” ๊ฒƒ์œผ๋กœ ์ •์˜๋˜๊ณ  ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๊ฐ€ ๋ฐ˜ํ™˜ํ•˜๋Š” ๊ฒƒ์€ Foo ๊ฐ€ ๋ฌด์—‡์ธ์ง€์— ์˜ํ•ด ์ •์˜๋ฉ๋‹ˆ๋‹ค. ๊ทธ๋“ค์€ ๋–ผ๋ ค์•ผ ๋—„ ์ˆ˜ ์—†์ด ์—ฐ๊ฒฐ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.

๋‚˜๋Š” ์ด๊ฒƒ์„ ๊ตฌํ˜„ํ•˜๋Š” ๊ฒƒ์ด ๋งค์šฐ ์–ด๋ ค์šธ ๊ฒƒ์ด๋ผ๊ณ  ํ™•์‹ ํ•ฉ๋‹ˆ๋‹ค.

๊ธฐ๋Šฅ์ด ์–ด๋–ป๊ฒŒ ์ž‘๋™ํ•ด์•ผ ํ•˜๋Š”์ง€์— ๋Œ€ํ•œ ํ™•์‹คํ•œ ์ œ์•ˆ์ด ์—†๋Š” ์ƒํ™ฉ์—์„œ ๊ตฌํ˜„ ๋ณต์žก์„ฑ์— ๋Œ€ํ•ด ์ด์•ผ๊ธฐํ•˜๋Š” ๊ฒƒ์€ ์•„์ง ์‹œ๊ธฐ์ƒ์กฐ์ž…๋‹ˆ๋‹ค. ์ด๋Ÿฐ ๋ง์„ ํ•ด์„œ ์ฃ„์†กํ•ฉ๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ "์ด์™€ ๊ฐ™์€ ์ผ๋ จ์˜ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋ฅผ ํ•ด๋‹น ํด๋ž˜์Šค์— ์ ์šฉํ•˜๋ฉด this ์— ์–ด๋–ค ์ผ์ด ๋ฐœ์ƒํ•˜๋Š”์ง€"์— ๋Œ€ํ•œ ๊ตฌ์ฒด์ ์ธ ๋ฉ”์ปค๋‹ˆ์ฆ˜์„ ์ œ์•ˆํ•  ์‚ฌ๋žŒ์ด ์ •๋ง๋กœ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฐ ๋‹ค์Œ ๋‹ค๋ฅธ ๋ถ€๋ถ„์— ๋‹ค์–‘ํ•œ TypeScript ๊ฐœ๋…์„ ์—ฐ๊ฒฐํ•˜๊ณ  ๊ฒฐ๊ณผ๊ฐ€ ์˜๋ฏธ๊ฐ€ ์žˆ๋Š”์ง€ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ž˜์•ผ๋งŒ ๊ตฌํ˜„ ๋ณต์žก์„ฑ์„ ๋…ผ์˜ํ•˜๋Š” ๊ฒƒ์ด ํ•ฉ๋ฆฌ์ ์ž…๋‹ˆ๋‹ค.

์œ„์— ๋ถ™์—ฌ ๋„ฃ์€ ํ˜„์žฌ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ ์ถœ๋ ฅ์ด ์‚ฌ์–‘์„ ์ค€์ˆ˜ํ•˜์ง€ ์•Š์Šต๋‹ˆ๊นŒ? ๋‚ด๊ฐ€ ๋ณธ ๊ฒƒ์—์„œ ๋น„๋กฏ๋œ ๊ฒƒ์ด๋ผ๊ณ  ์ƒ๊ฐํ–ˆ๋‹ค.

๊ทธ๋ ‡๋‹ค๊ณ  ๊ฐ€์ •ํ•˜๋ฉด Foo๋Š” ๋ชจ๋“  ๋‹จ๊ณ„์—์„œ ์ƒ๋‹นํžˆ ์ •ํ™•ํ•œ ์˜๋ฏธ๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ๋‚˜๋Š” TS๊ฐ€ ๋งˆ์ง€๋ง‰ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๊ฐ€ ๋ฐ˜ํ™˜ํ•˜๋Š” ๊ฒƒ์„ ๊ธฐ๋ฐ˜์œผ๋กœ this (Foo ๋ฉ”์„œ๋“œ ๋‚ด๋ถ€ ๋ฐ Foo ์ธ์Šคํ„ด์Šค์—์„œ)๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ํ—ˆ์šฉํ•  ๊ฒƒ์œผ๋กœ ์˜ˆ์ƒํ•ฉ๋‹ˆ๋‹ค. ๊ธฐ๋Šฅ์„ ์ถฉ๋ถ„ํžˆ ๋ถ„์„ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

@arackaf "๋‹จ๊ณ„"๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. ์šฐ๋ฆฌ๋Š” ์ฃผ์–ด์ง„ ๋ถˆ๋ณ€ ์ฝ”๋“œ ์กฐ๊ฐ์— ๋Œ€ํ•œ this ์˜ ์ตœ์ข… ์œ ํ˜•์—๋งŒ ๊ด€์‹ฌ์ด ์žˆ์Šต๋‹ˆ๋‹ค. this ์˜ ์œ ํ˜•์ด X ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ ํ•จ์ˆ˜ f1...fn ๋กœ ์žฅ์‹๋œ X ์˜ ๋ฉค๋ฒ„์— ๋Œ€ํ•ด ์–ด๋–ค ์œ ํ˜•์ด ๋˜์–ด์•ผ ํ•˜๋Š”์ง€๋ฅผ ์ตœ์†Œํ•œ ๋†’์€ ์ˆ˜์ค€์—์„œ ์„ค๋ช…ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. X ๋ฐ f1...fn ์˜ ์œ ํ˜• ์„œ๋ช… ์ค‘. ์›ํ•˜๋Š” ๋งŒํผ ํ”„๋กœ์„ธ์Šค ๋‹จ๊ณ„๋ฅผ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ง€๊ธˆ๊นŒ์ง€ ์•„๋ฌด๋„ ์ด๊ฒƒ์„ ํ•˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค. ๋‚˜๋Š” ์‚ฌ๋žŒ๋“ค์ด ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ์˜ ๋ฐ˜ํ™˜ ์œ ํ˜•์ด this ์˜ ์œ ํ˜•์œผ๋กœ ํ‘œ์‹œ๋˜์–ด์•ผ ํ•œ๋‹ค๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•œ๋‹ค๊ณ  ์ถ”์ธกํ•ด ์™”์ง€๋งŒ ๋‚ด๊ฐ€ ์•„๋Š” ํ•œ ๋‚˜๋Š” ์™„์ „ํžˆ ํ‹€๋ฆด ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋‹น์‹ ์˜ ์ œ์•ˆ์ด ๋ณ€ํ™˜๋œ ์ถœ๋ ฅ์˜ ๊ฐ’์— ์–ด๋–ค ์ผ์ด ์ผ์–ด๋‚˜๋Š”์ง€๋ฅผ ๊ธฐ๊ณ„์ ์œผ๋กœ ๋ฐ˜์˜ํ•˜๋„๋ก ํ•˜๋Š” ๊ฒƒ์ด๋ผ๋ฉด ๋‹น์‹ ์€ ๋‹น์‹ ์ด ์ œ์•ˆํ•˜๋Š” ๊ฒƒ ๋Œ€์‹ ์— ๋‚ด๊ฐ€ ์ œ์•ˆํ•˜๋Š” ๊ฒƒ์œผ๋กœ ๋๋‚ฉ๋‹ˆ๋‹ค: ์˜ˆ๋ฅผ ๋“ค์–ด new Foo().hello() ๋Š” ๊ดœ์ฐฎ์ง€๋งŒ this.hello() ์€(๋Š”) ์•„๋‹™๋‹ˆ๋‹ค. ์ด ์˜ˆ์ œ์˜ ์–ด๋–ค ์‹œ์ ์—์„œ๋„ ์žฅ์‹ํ•˜๊ณ  ์žˆ๋Š” ์›๋ž˜ ํด๋ž˜์Šค๋Š” hello ๋ฉ”์„œ๋“œ๋ฅผ ์–ป์ง€ ๋ชปํ•ฉ๋‹ˆ๋‹ค. __decorate([addMethod], Foo) ( Foo ์— ํ• ๋‹น๋จ)์˜ ๊ฒฐ๊ณผ์—๋งŒ hello ๋ฉ”์„œ๋“œ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

๋‚˜๋Š” ์‚ฌ๋žŒ๋“ค์ด ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ์˜ ๋ฐ˜ํ™˜ ์œ ํ˜•์ด ์ด๊ฒƒ์˜ ์œ ํ˜•์œผ๋กœ ํ‘œ์‹œ๋˜์–ด์•ผ ํ•จ์„ ์˜๋ฏธํ•œ๋‹ค๊ณ  ์ถ”์ธกํ–ˆ์Šต๋‹ˆ๋‹ค.

์•„, ์ฃ„์†กํ•ฉ๋‹ˆ๋‹ค. ๋„ค, ๋งž์Šต๋‹ˆ๋‹ค. ์ •ํ™•ํžˆ ๊ทธ. ๋งˆ์นจํ‘œ. ๊ทธ๊ฒƒ์ด ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๊ฐ€ ํ•˜๋Š” ์ผ์ด๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ์ค„์˜ ๋งˆ์ง€๋ง‰ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๊ฐ€ ์™„์ „ํžˆ ์ƒˆ๋กœ์šด ํด๋ž˜์Šค๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋ฉด ๊ทธ๊ฒƒ์ด ๋ฐ”๋กœ Foo์ž…๋‹ˆ๋‹ค.

๋‹ค์‹œ ๋งํ•ด:

<strong i="9">@c</strong>
<strong i="10">@b</strong>
<strong i="11">@a</strong>
class Foo { 
}

Foo๋Š” c ๊ฐ€ ๋งํ•˜๋Š” ์„ธ์ƒ ๋ฌด์—‡์ด๋“  ๋ฉ๋‹ˆ๋‹ค. c ๊ฐ€ any ๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ํ•จ์ˆ˜๋ผ๋ฉด ์ €๋Š” ์ž˜ ๋ชจ๋ฅด๊ฒ ์Šต๋‹ˆ๋‹ค. ์•„๋งˆ๋„ ์›๋ž˜ Foo ๋กœ ๋Œ€์ฒด๋  ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๊ทธ๊ฒƒ์€ ํ•ฉ๋ฆฌ์ ์ด๊ณ  ์ด์ „ ๋ฒ„์ „๊ณผ ํ˜ธํ™˜๋˜๋Š” ์ ‘๊ทผ ๋ฐฉ์‹์ฒ˜๋Ÿผ ๋ณด์ž…๋‹ˆ๋‹ค.

ํ•˜์ง€๋งŒ c ๊ฐ€ ์ƒˆ๋กœ์šด ์œ ํ˜• X $ ์„ ๋ฐ˜ํ™˜ํ•˜๋ฉด Foo๊ฐ€ ์ด๋ฅผ ์กด์ค‘ํ•  ๊ฒƒ์œผ๋กœ ๊ธฐ๋Œ€ํ•ฉ๋‹ˆ๋‹ค.

๋‚ด๊ฐ€ ๋ญ”๊ฐ€๋ฅผ ๋†“์น˜๊ณ  ์žˆ์Šต๋‹ˆ๊นŒ?


์ถ”๊ฐ€๋กœ ๋ช…ํ™•ํžˆ ํ•˜๋Š” ๊ฒฝ์šฐ

class X { 
    hello() {}
    world() {}
}
function c(cl : any) : X {  // or should it be typeof X ?????
    //...
}

<strong i="25">@c</strong>
<strong i="26">@b</strong>
<strong i="27">@a</strong>
class Foo { 
    sorry() {}
}

new Foo().hello(); //perfectly valid
new Foo().sorry(); //ERROR 

๋‚ด๊ฐ€ ๋ญ”๊ฐ€๋ฅผ ๋†“์น˜๊ณ  ์žˆ์Šต๋‹ˆ๊นŒ?

@arackaf ์˜ˆ, ์ด ์ˆœ์ง„ํ•œ ์ ‘๊ทผ ๋ฐฉ์‹์ด ๋น ์ ธ ์žˆ๋Š” ๊ฒƒ์€ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๊ฐ€ ์ž„์˜์˜ ์œ ํ˜•์„ ์ž์œ ๋กญ๊ฒŒ ๋ฐ˜ํ™˜ํ•  ์ˆ˜ ์žˆ๊ณ  ๊ฒฐ๊ณผ๊ฐ€ Foo ์œ ํ˜•๊ณผ ํ˜ธํ™˜๋œ๋‹ค๋Š” ์ œํ•œ์ด ์—†๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์ด๊ฒƒ์œผ๋กœ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋Š” ๋ถ€์กฐ๋ฆฌ์˜ ์ˆ˜๋Š” ์–ผ๋งˆ๋“ ์ง€ ์žˆ์Šต๋‹ˆ๋‹ค. c this ๋ฅผ ์ž…๋ ฅํ•˜๋Š” ์ˆœํ™˜์„ฑ์— ๋Œ€ํ•œ ๋‚ด ์ด์˜๋ฅผ ๋ณด๋ฅ˜ํ•œ๋‹ค๊ณ  ๊ฐ€์ •ํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. this ์˜ ์œ ํ˜•์— ๋”ฐ๋ผ ๊ฒฐ์ •๋˜๋ฉฐ, ์ด๋Š” c ๋“ฑ. ์—ฌ์ „ํžˆ ์ž‘๋™ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์—ฌ๊ธฐ ๋˜ ๋‹ค๋ฅธ ๋ฌด์˜๋ฏธํ•œ ์˜ˆ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

type Constructor<T> = new (...args: any[]) => T
type Greeter = { hello(): string }

function logger<T extends Constructor<Greeter>>(Class: T) {
    return class {
        hello() {
            console.log(new Class().hello())
        }
    };
}


<strong i="15">@logger</strong>
class Foo {
    foo() { return "bar" }
    // Whoops, `this` is `{ hello(): void }`, it has no `foo` method
    hello() { return this.foo(); }
}

์ด ๊ฒฝ์šฐ ์™„์ „ํžˆ ๋ฌดํ•ดํ•œ ์ฝ”๋“œ์— ๋Œ€ํ•ด ์˜ค๋ฅ˜๋ฅผ ์ƒ์„ฑํ•˜๊ฑฐ๋‚˜ this ๊ฐ€ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ์˜ ๋ฐ˜ํ™˜ ์œ ํ˜•๊ณผ ์ •ํ™•ํžˆ ๋™์ผํ•˜๋‹ค๋Š” ๋ช…์ œ๋ฅผ ์กฐ์ •ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

๋ฌธ์ œ๊ฐ€ ์žˆ๋Š”์ง€ ์ž˜ ๋ชจ๋ฅด๊ฒ ์Šต๋‹ˆ๋‹ค. @logger ์€ foo ๋ฉ”์„œ๋“œ ์—†์ด ์™„์ „ํžˆ ์ƒˆ๋กœ์šด hello() ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์™„์ „ํžˆ ์ƒˆ๋กœ์šด ํด๋ž˜์Šค๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋„๋ก ์„ ํƒํ–ˆ์Šต๋‹ˆ๋‹ค. Foo .

new Foo().foo()

๋” ์ด์ƒ ์œ ํšจํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋Ÿฐํƒ€์ž„ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค. ๋‚˜๋Š” ๊ทธ๊ฒƒ์ด ๋˜ํ•œ ์ปดํŒŒ์ผ ํƒ€์ž„ ์˜ค๋ฅ˜๋ฅผ ์ƒ์„ฑํ•ด์•ผํ•œ๋‹ค๊ณ  ๋งํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

์ฆ‰, ๋ชจ๋“  ๊ฒƒ์„ ์ •์ ์œผ๋กœ ๋ถ„์„ํ•˜๋Š” ๊ฒƒ์ด ๋„ˆ๋ฌด ์–ด๋ ต๋‹ค๋ฉด ๋ฐ˜ํ™˜๋˜๋Š” ๋‚ด์šฉ์„ ์ •ํ™•ํžˆ ๋‚˜ํƒ€๋‚ด๊ธฐ ์œ„ํ•ด ๋ช…์‹œ์  ์œ ํ˜• ์ฃผ์„์„ logger ์— ์ถ”๊ฐ€ํ•˜๋„๋ก ๊ฐ•์ œํ•˜๋Š” ๊ฒƒ์ด ์™„์ „ํžˆ ํ•ฉ๋ฆฌ์ ์ผ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ๊ทธ๋Ÿฌํ•œ ์œ ํ˜• ์ฃผ์„์ด ์—†์œผ๋ฉด Foo ๊ฐ€ ๋‹ค์‹œ ๋ฐ˜ํ™˜๋œ๋‹ค๊ณ  ๊ฐ€์ •ํ•˜๋Š” ๊ฒƒ์œผ๋กœ ๋˜๋Œ๋ฆด ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๊ฒƒ์€ ์ด์ „ ๋ฒ„์ „๊ณผ์˜ ํ˜ธํ™˜์„ฑ์„ ์œ ์ง€ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

@arackaf ํƒ€์ดํ•‘์ด๋‚˜ ๋Ÿฐํƒ€์ž„ ํ‰๊ฐ€ ์ธก๋ฉด์—์„œ ์ฝ”๋“œ์—๋Š” ๋ฌธ์ œ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. new Foo().hello() ๋ฅผ ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ์ด๋Š” ๋‚ด๋ถ€์ ์œผ๋กœ ์žฅ์‹๋œ ํด๋ž˜์Šค์˜ hello ๋ฅผ ํ˜ธ์ถœํ•˜๊ณ , ์ด๋Š” ์žฅ์‹๋œ ํด๋ž˜์Šค์˜ bar ๋ฅผ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค. ์›๋ž˜ ํด๋ž˜์Šค ๋‚ด์—์„œ bar ๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ๊ฒƒ์€ ์˜ค๋ฅ˜๊ฐ€ ์•„๋‹™๋‹ˆ๋‹ค.

ํ”Œ๋ ˆ์ด๊ทธ๋ผ์šด๋“œ์—์„œ ๋‹ค์Œ ์ „์ฒด ์˜ˆ์ œ๋ฅผ ์‹คํ–‰ํ•˜์—ฌ ์ง์ ‘ ์‚ฌ์šฉํ•ด ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

// Code from previous snippet...

const LoggerFoo = logger(Foo)
new LoggerFoo().hello()

๋ฌผ๋ก ์ž…๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ํ˜ธ์ถœํ•˜๋Š” ๋ฐ ์˜ค๋ฅ˜๊ฐ€ ์žˆ๋‹ค๊ณ  ๋งํ–ˆ์Šต๋‹ˆ๋‹ค.

new Foo().foo()

ํƒ€์ดํ•‘์ด๋‚˜ ๋Ÿฐํƒ€์ž„ ํ‰๊ฐ€ ์ธก๋ฉด์—์„œ ์ฝ”๋“œ์—๋Š” ๋ฌธ์ œ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. new Foo().hello()๋ฅผ ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋‚ด๋ถ€์ ์œผ๋กœ ์žฅ์‹๋œ ํด๋ž˜์Šค์˜ hello๋ฅผ ํ˜ธ์ถœํ•˜๊ณ  ์žฅ์‹๋œ ํด๋ž˜์Šค์˜ ๋ง‰๋Œ€๋ฅผ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค.

๊ทธ๋Ÿฌ๋‚˜ ๊ทธ๊ฒƒ์€ ์˜ค๋ฅ˜๋ผ๊ณ  ๋งํ•ด์•ผํ•ฉ๋‹ˆ๋‹ค.

let s : string = new Foo().hello();

Foo์˜ hello ๋ฉ”์„œ๋“œ๋Š” ์ด์ œ Logger๊ฐ€ ๋ฐ˜ํ™˜ํ•˜๋Š” ํด๋ž˜์Šค๋ณ„๋กœ void๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

๋ฌผ๋ก ์ž…๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ new Foo().foo() ๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ๊ฒƒ์€ ์˜ค๋ฅ˜๋ผ๊ณ  ๋งํ–ˆ์Šต๋‹ˆ๋‹ค.

@arackaf ํ•˜์ง€๋งŒ ๊ทธ๊ฑด ์ค‘์š”ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. new Foo().foo() ๋ฅผ ํ˜ธ์ถœํ•˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค. this.foo() ๋ฅผ ํ˜ธ์ถœํ–ˆ๋Š”๋ฐ ์ฝ”๋“œ๊ฐ€ ๋Ÿฐํƒ€์ž„์— ์ œ๋Œ€๋กœ ์ž‘๋™ํ•˜๋Š”๋ฐ๋„ ์œ ํ˜• ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค.

ํ•˜์ง€๋งŒ let s : string = new Foo().hello() ๋ผ๊ณ  ๋งํ•˜๋Š” ๊ฒƒ์€ ์˜ค๋ฅ˜์—ฌ์•ผ ํ•ฉ๋‹ˆ๋‹ค.

๋‹ค์‹œ ๋งํ•˜์ง€๋งŒ ์ด๊ฒƒ์€ ๊ด€๋ จ์ด ์—†์Šต๋‹ˆ๋‹ค. Foo.prototype.hello () => string ํ•œ๋‹ค๊ณ  ๋งํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹™๋‹ˆ๋‹ค( () => void ์ด์–ด์•ผ ํ•œ๋‹ค๋Š” ๋ฐ ๋™์˜ํ•ฉ๋‹ˆ๋‹ค). ๋‚˜๋Š” ์œ ํšจํ•œ ํ˜ธ์ถœ this.bar() ์˜ค๋ฅ˜์— ๋Œ€ํ•ด ๋ถˆํ‰ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ์ด์‹ํ•˜๋Š” ๊ฒƒ์ด ๋ฌด์˜๋ฏธํ•œ ์œ ํ˜•์„ ์™ธ๊ณผ์ ์œผ๋กœ ์ด์‹ํ–ˆ๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

์—ฌ๊ธฐ์— ๋‘ ๊ฐœ์˜ ํ‘ธ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ๋‹น์‹ ์ด ๋งํ•  ๋•Œ

class Foo { 
}

Foo๋Š” ํด๋ž˜์Šค ๋‚ด๋ถ€์˜ ๋ณ€๊ฒฝ ๋ถˆ๊ฐ€๋Šฅํ•œ ๋ฐ”์ธ๋”ฉ์ด๊ณ  ํด๋ž˜์Šค ์™ธ๋ถ€์˜ ๋ณ€๊ฒฝ ๊ฐ€๋Šฅํ•œ ๋ฐ”์ธ๋”ฉ์ž…๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ jsbin์—์„œ ํ™•์ธํ•  ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ ์™„๋ฒฝํ•˜๊ฒŒ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค.

class Foo { 
  static sMethod(){
    alert('works');
  }
  hello(){ 
    Foo.sMethod();
  }
}

let F = Foo;

Foo = null;

new F().hello();

์œ„์˜ ์˜ˆ๋Š” ๋น„์Šทํ•œ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค. ์™ธ๋ถ€ ๋ฐ”์ธ๋”ฉ์ด ๋ณ€๊ฒฝ๋˜๊ธฐ ์ „์— ์›๋ž˜ ํด๋ž˜์Šค์— ๋Œ€ํ•œ ์ฐธ์กฐ๋ฅผ ์บก์ฒ˜ํ•ฉ๋‹ˆ๋‹ค. ๋‚˜๋Š” ์•„์ง๋„ ๋‹น์‹ ์ด ๋ฌด์—‡์„ ์šด์ „ํ•˜๊ณ  ์žˆ๋Š”์ง€ ์ž˜ ๋ชจ๋ฅด๊ฒ ์Šต๋‹ˆ๋‹ค.

this.foo(); ๋Š” ์™„๋ฒฝํ•˜๊ฒŒ ์œ ํšจํ•˜๋ฉฐ ์œ ํ˜• ์˜ค๋ฅ˜๋ฅผ ์˜ˆ์ƒํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค(์ฐธ์กฐ๊ฐ€ ํ•„์š”ํ•œ ๊ฒฝ์šฐ TS ์‚ฌ๋žŒ์„ ๋น„๋‚œํ•˜์ง€๋„ ์•Š์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ด๊ฒƒ์„ ์ถ”์ ํ•˜๋Š” ๊ฒƒ์ด ์–ด๋ ค์šธ ๊ฒƒ์ด๋ผ๊ณ  ํ™•์‹ ํ•˜๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค)

this.foo(); ๋Š” ์™„๋ฒฝํ•˜๊ฒŒ ์œ ํšจํ•˜๋ฉฐ ์œ ํ˜• ์˜ค๋ฅ˜๋ฅผ ์˜ˆ์ƒํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์ข‹์Šต๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ ์šฐ๋ฆฌ๋Š” ๋™์˜ํ•ฉ๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ์ด๊ฒƒ์€ ์ด์ œ this ๊ฐ€ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๊ฐ€ ๋ฐ˜ํ™˜ํ•˜๋Š” ๋ชจ๋“  ์ธ์Šคํ„ด์Šค ์œ ํ˜•์ด ๋˜์–ด์•ผ ํ•œ๋‹ค๋Š” ์ œ์•ˆ์„ ์Šน์ธํ•˜๊ฑฐ๋‚˜ ๊ธฐ๊ฐํ•ด์•ผ ํ•จ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค. ์œ ํ˜• ์˜ค๋ฅ˜๊ฐ€ ์•„๋‹ˆ์–ด์•ผ ํ•œ๋‹ค๊ณ  ์ƒ๊ฐํ•œ๋‹ค๋ฉด ๋‚ด ์˜ˆ์—์„œ { hello(): void } ๋Œ€์‹  this ๊ฐ€ ๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๊นŒ?

this ๋Š” ์ธ์Šคํ„ด์Šคํ™”๋œ ํ•ญ๋ชฉ์— ๋”ฐ๋ผ ๋‹ค๋ฆ…๋‹ˆ๋‹ค.

<strong i="7">@c</strong>
class Foo{
}

new Foo(). // <---- this is based on whatever c returned 

function c(Cl){
    new Cl().  // <----- this is an object whose prototype is the original Foo's prototype
                   // but for TS's purpose, for type errors, it'd depend on how Cl is typed
}

ํ•œ ๊ฐ€์ง€ ๊ตฌ์ฒด์ ์ธ ์˜ˆ๋ฅผ ๋“ค์–ด๋ณผ๊นŒ์š”? ๊ทธ๋ ‡๊ฒŒ ํ•˜๋ฉด ํ›จ์”ฌ ๋” ์ดํ•ดํ•˜๊ธฐ ์‰ฌ์šธ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋‹ค์Œ ์Šค๋‹ˆํŽซ์—์„œ:

type Constructor<T> = new (...args: any[]) => T
type Greeter = { hello(): string }

function logger<T extends Constructor<Greeter>>(Class: T) {
    return class {
        hello() {
            console.log(new Class().hello())
        }
    };
}

<strong i="6">@logger</strong>
class Foo {
    foo() { return "bar" }
    hello() { return this.foo(); } /// <------
}

this ์˜ ์œ ํ˜•์€ ๋ฌด์—‡์ž…๋‹ˆ๊นŒ? { hello(): void } ์ด๋ฉด foo ๊ฐ€ { hello(): void } ์˜ ๊ตฌ์„ฑ์›์ด ์•„๋‹ˆ๊ธฐ ๋•Œ๋ฌธ์— ์œ ํ˜• ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค. { hello(): void } ๊ฐ€ ์•„๋‹ˆ๋ฉด this ๋Š” ๋‹จ์ˆœํžˆ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ ๋ฐ˜ํ™˜ ์œ ํ˜•์˜ ์ธ์Šคํ„ด์Šค ์œ ํ˜•์ด ์•„๋‹ˆ๋ฉฐ $# ์œ ํ˜•์— ๋„๋‹ฌํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉํ•˜๋Š” ๋Œ€์ฒด ๋…ผ๋ฆฌ๋ฅผ ์„ค๋ช…ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค this .

ํŽธ์ง‘: Foo ์— ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋ฅผ ์ถ”๊ฐ€ํ•˜๋Š” ๊ฒƒ์„ ์žŠ์—ˆ์Šต๋‹ˆ๋‹ค. ๊ฒฐ์ •๋œ.

ํ™”์‚ดํ‘œ๊ฐ€ ์žˆ๋Š” this ๋Š” ๋ฌผ๋ก  ์›๋ž˜ Foo ์˜ ์ธ์Šคํ„ด์Šค์ž…๋‹ˆ๋‹ค. ์œ ํ˜• ์˜ค๋ฅ˜๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.

์•„ - ์ด์ œ ์š”์ ์„ ์•Œ์•˜์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๋‚˜๋Š” ์—ฌ์ „ํžˆ ๋ฌธ์ œ๊ฐ€ ์–ด๋””์— ์žˆ๋Š”์ง€ ์•Œ์ง€ ๋ชปํ•ฉ๋‹ˆ๋‹ค. this.foo() WITHIN ์›๋ž˜ Foo ๋Š” ์œ ํ˜• ์˜ค๋ฅ˜๊ฐ€ ์•„๋‹™๋‹ˆ๋‹ค. ์ด๋Š” Foo ์‹๋ณ„์ž์— ๋ฐ”์ธ๋”ฉ๋œ (์ง€๊ธˆ์€ ์—ฐ๊ฒฐํ•  ์ˆ˜ ์—†๋Š”) ํด๋ž˜์Šค์— ์œ ํšจํ•ฉ๋‹ˆ๋‹ค.

๋…ํŠนํ•˜๊ณ  ์žฌ๋ฏธ์žˆ๋Š” ์ƒ์‹์ด์ง€๋งŒ ์ด๊ฒƒ์ด TS๊ฐ€ ๋Œ์—ฐ๋ณ€์ด ํด๋ž˜์Šค ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋ฅผ ์ฒ˜๋ฆฌํ•˜๋Š” ๊ฒƒ์„ ๋ง‰์•„์•ผ ํ•˜๋Š” ์ด์œ ๋ฅผ ๋ชจ๋ฅด๊ฒ ์Šต๋‹ˆ๋‹ค.

@arackaf ๋‹น์‹ ์€ ์งˆ๋ฌธ์— ๋Œ€๋‹ตํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๊ตฌ์ฒด์ ์œผ๋กœ this ์˜ ์œ ํ˜•์€ ๋ฌด์—‡์ž…๋‹ˆ๊นŒ? " this is Foo and Foo is this "๋ผ๊ณ  ๋์—†์ด ์ˆœํ™˜์ ์œผ๋กœ ๋Œ€๋‹ตํ•  ์ˆ˜๋Š” ์—†์Šต๋‹ˆ๋‹ค. this ์˜ ๋ฉค๋ฒ„๋Š”? hello(): void ์ด์™ธ์˜ ๋ฉค๋ฒ„๊ฐ€ ์žˆ๋Š” ๊ฒฝ์šฐ ๋ฉค๋ฒ„๋ฅผ ๊ฒฐ์ •ํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ๋˜๋Š” ๋…ผ๋ฆฌ๋Š” ๋ฌด์—‡์ž…๋‹ˆ๊นŒ?

" this.foo() WITHIN original Foo is not type error"๋ผ๊ณ  ๋งํ•  ๋•Œ์—๋„ ์—ฌ์ „ํžˆ ๋‹ค์Œ ์งˆ๋ฌธ์— ๋‹ตํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. this ์˜ ๊ตฌ์กฐ์  ์œ ํ˜•์€ ๋ฌด์—‡์ด๋ฉฐ ์œ ํ˜• ์˜ค๋ฅ˜๊ฐ€ ์•„๋‹™๋‹ˆ๋‹ค. this.foo() ํ•ฉ๋‹ˆ๊นŒ?

๋˜ํ•œ ์›๋ž˜ ํด๋ž˜์Šค๋Š” "์ ‘๊ทผํ•  ์ˆ˜ ์—†์Œ"์ด ์•„๋‹™๋‹ˆ๋‹ค. ํ•ด๋‹น ์ฝ”๋“œ ์กฐ๊ฐ์— ์ •์˜๋œ ๋ชจ๋“  ๊ธฐ๋Šฅ์€ ๋Ÿฐํƒ€์ž„์— ๋Šฅ๋™์ ์œผ๋กœ ์‹คํ–‰๋˜๋ฉฐ ๋ชจ๋‘ ๋ฌธ์ œ ์—†์ด ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค. ์ œ๊ฐ€ ์ œ๊ณตํ•œ ํ”Œ๋ ˆ์ด๊ทธ๋ผ์šด๋“œ ๋งํฌ๋ฅผ ์‹คํ–‰ํ•˜์…”์„œ ์ฝ˜์†”์„ ๋ด์ฃผ์„ธ์š”. ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋Š” hello ๋ฉ”์„œ๋“œ๊ฐ€ ๋ฐ์ฝ”๋ ˆ์ดํŒ…๋œ ํด๋ž˜์Šค์˜ hello ๋ฉ”์„œ๋“œ์— ์œ„์ž„๋œ ์ƒˆ ํด๋ž˜์Šค๋ฅผ ๋ฐ˜ํ™˜ํ•˜๊ณ , ์ด ํด๋ž˜์Šค๋Š” ์ฐจ๋ก€๋กœ ๋ฐ์ฝ”๋ ˆ์ดํŒ…๋œ ํด๋ž˜์Šค์˜ foo ๋ฉ”์„œ๋“œ์— ์œ„์ž„ํ•ฉ๋‹ˆ๋‹ค.

๋…ํŠนํ•˜๊ณ  ์žฌ๋ฏธ์žˆ๋Š” ์ƒ์‹์ด์ง€๋งŒ ์ด๊ฒƒ์ด TS๊ฐ€ ๋Œ์—ฐ๋ณ€์ด ํด๋ž˜์Šค ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋ฅผ ์ฒ˜๋ฆฌํ•˜๋Š” ๊ฒƒ์„ ๋ง‰์•„์•ผ ํ•˜๋Š” ์ด์œ ๋ฅผ ๋ชจ๋ฅด๊ฒ ์Šต๋‹ˆ๋‹ค.

์œ ํ˜• ์‹œ์Šคํ…œ์—๋Š” "ํŠธ๋ฆฌ๋น„์•„"๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. ์‚ฌ์šฉ ์‚ฌ๋ก€๊ฐ€ ๋„ˆ๋ฌด ํ‹ˆ์ƒˆ ์‹œ์žฅ์ด๊ธฐ ๋•Œ๋ฌธ์— TSC-1234 "naughty boy, you can't do that" ์œ ํ˜• ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๊ธฐ๋Šฅ์œผ๋กœ ์ธํ•ด ์™„์ „ํžˆ ์ •์ƒ์ ์ธ ์ฝ”๋“œ๊ฐ€ ๋†€๋ผ์šด ๋ฐฉ์‹์œผ๋กœ ์ค‘๋‹จ๋˜๋Š” ๊ฒฝ์šฐ ๊ธฐ๋Šฅ์„ ์žฌ๊ณ ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

์‚ฌ์šฉ ์‚ฌ๋ก€๊ฐ€ ๋„ˆ๋ฌด ํ‹ˆ์ƒˆ ์‹œ์žฅ์ด๊ธฐ ๋•Œ๋ฌธ์— TSC-1234 "naughty boy, you can't do that" ์œ ํ˜• ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์ด๊ฒƒ์ด ๋ฐ”๋กœ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๊ฐ€ ํด๋ž˜์Šค ์ •์˜์— ์ถ”๊ฐ€ํ•œ ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๋ ค๊ณ  ํ•  ๋•Œ ์–ป๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ํ˜„์žฌ ํด๋ž˜์Šค์— ์ •์˜๋ฅผ ์ถ”๊ฐ€ํ•˜๊ฑฐ๋‚˜ ์ธํ„ฐํŽ˜์ด์Šค ๋ณ‘ํ•ฉ, any ๋“ฑ์œผ๋กœ ์บ์ŠคํŒ…ํ•˜์—ฌ ์ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

this ๊ฐ€ ๋ฌด์—‡์ด๋ฉฐ ์–ด๋””์— ์žˆ๋Š”์ง€์— ๋Œ€ํ•œ ๋ชจ๋“  ์งˆ๋ฌธ์— ๋‹ต๋ณ€ํ–ˆ์Šต๋‹ˆ๋‹ค.

๋ฌธ์ œ์˜ ๊ฐ„๋‹จํ•œ ์‚ฌ์‹ค์€ this ์˜ ์˜๋ฏธ๋Š” ๋‹น์‹ ์ด ์–ด๋””์— ์žˆ๋Š๋ƒ์— ๋”ฐ๋ผ ๋‹ฌ๋ผ์ง„๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

type Constructor<T> = new (...args: any[]) => T
type Greeter = { hello(): string }

function logger<T extends Constructor<Greeter>>(Class: T) {
    return class {
        hello() {
            console.log(new Class().hello())
        }
    };
}

class Foo {
    foo() { return "bar" }
    hello() { return this.foo(); } /// <------
}

const LoggableFoo = logger(Foo)
new LoggableFoo().hello() // Logs "bar"

new Class() - ํด๋ž˜์Šค๊ฐ€ ์›๋ž˜ Foo๋ฅผ ๊ฐ€๋ฆฌํ‚ค๊ณ  ์žˆ๊ณ  TypeScript์˜ ๊ด€์ ์—์„œ ๋ณด๋ฉด ํด๋ž˜์Šค๊ฐ€ ์ž…๋ ฅ๋˜๋Š” ํ˜•์‹์ด๊ธฐ ๋•Œ๋ฌธ์— hello(): string ์— ์•ก์„ธ์Šคํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค(Greeter ํ™•์žฅ). ๋Ÿฐํƒ€์ž„์— ์›๋ž˜ Foo์˜ ์ธ์Šคํ„ด์Šค๋ฅผ ์ธ์Šคํ„ด์Šคํ™”ํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

new LoggableFoo().hello() ๋Š” Greeter๋ฅผ ํ†ตํ•ด ์ž…๋ ฅํ•œ ๋‹ค๋ฅธ ๋ฐฉ๋ฒ•์œผ๋กœ๋Š” ๋„๋‹ฌํ•  ์ˆ˜ ์—†๋Š” ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜๋Š” void ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค.

ํ–ˆ๋‹ค๋ฉด

<strong i="21">@logger</strong>
class Foo {
    foo() { return "bar" }
    hello() { return this.foo(); }
}

๊ทธ๋Ÿฌ๋ฉด Foo๋Š” ์ด์ œ hello(): void๋งŒ ์žˆ๋Š” ํด๋ž˜์Šค์ด๊ณ  new Foo().foo()๋Š” ์œ ํ˜• ์˜ค๋ฅ˜์—ฌ์•ผ ํ•ฉ๋‹ˆ๋‹ค.

๊ทธ๋ฆฌ๊ณ  ๋‹ค์‹œ hello() { return this.foo(); } ๋Š” TypeError๊ฐ€ ์•„๋‹™๋‹ˆ๋‹ค. ์™œ ๊ทธ๋Ÿฐ๊ฐ€์š”? ํ•ด๋‹น ํด๋ž˜์Šค ์ •์˜์— ๋” ์ด์ƒ ์—ฐ๊ฒฐํ•  ์ˆ˜ ์—†๋‹ค๊ณ  ํ•ด์„œ ํ•ด๋‹น ๋ฉ”์„œ๋“œ๊ฐ€ ๋ฌดํšจํ™”๋˜๋Š” ๊ฒƒ์€ ์•„๋‹™๋‹ˆ๋‹ค.

TypeScript๊ฐ€ ์ด๋Ÿฌํ•œ ๊ทน๋‹จ์ ์ธ ๊ฒฝ์šฐ๋ฅผ ์™„๋ฒฝํ•˜๊ฒŒ ๋งŒ๋“ค ๊ฒƒ์ด๋ผ๊ณ  ๊ธฐ๋Œ€ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์–ธ์ œ๋‚˜์ฒ˜๋Ÿผ ์—ฌ๊ธฐ ์ €๊ธฐ์— ์œ ํ˜• ์ฃผ์„์„ ์ถ”๊ฐ€ํ•ด์•ผ ํ•˜๋Š” ๊ฒƒ์€ ๊ฝค ์ดํ•ดํ•  ๋งŒํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์ด๋Ÿฌํ•œ ์˜ˆ ์ค‘ ์–ด๋–ค ๊ฒƒ๋„ @logger ๊ฐ€ Foo ์˜ ๋ฐ”์ธ๋”ฉ ๋Œ€์ƒ์„ ๊ทผ๋ณธ์ ์œผ๋กœ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์—†๋Š” ์ด์œ ๋ฅผ ๋ณด์—ฌ์ฃผ์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

logger ๊ฐ€ ์ƒˆ ํด๋ž˜์Šค๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ํ•จ์ˆ˜์ด๋ฉด Foo๊ฐ€ ์ด์ œ ์ฐธ์กฐํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๋‚˜๋Š” ์ด๊ฒƒ์ด ๋ฌด์—‡์ด๋ฉฐ ์–ด๋””์— ์žˆ๋Š”์ง€์— ๋Œ€ํ•œ ๋ชจ๋“  ์งˆ๋ฌธ์— ๋‹ตํ–ˆ์Šต๋‹ˆ๋‹ค.
๋ฌธ์ œ์˜ ๊ฐ„๋‹จํ•œ ์‚ฌ์‹ค์€ this ์˜ ์˜๋ฏธ๊ฐ€ ๋‹น์‹ ์ด ์–ด๋””์— ์žˆ๋Š๋ƒ์— ๋”ฐ๋ผ ๋‹ฌ๋ผ์ง„๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์ •๋ง ๋‹ต๋‹ตํ•ฉ๋‹ˆ๋‹ค. ์ข‹์•„์š”, ๋ณ€๊ฒฝ๋ฉ๋‹ˆ๋‹ค. Foo , ์ •์  ๋ฐ”์ธ๋”ฉ ๋“ฑ์ž…๋‹ˆ๋‹ค. ํ˜•์‹ ์„œ๋ช…์€ ๋ฌด์—‡์ž…๋‹ˆ๊นŒ? this ์˜ ๋ฉค๋ฒ„๋Š”? ๋‚ด๊ฐ€ ๋‹น์‹ ์—๊ฒŒ ํ•„์š”ํ•œ ๊ฒƒ์€ this ๋‚ด๋ถ€์— hello ์— ๋Œ€ํ•œ ๊ฐ„๋‹จํ•œ ์œ ํ˜• ์„œ๋ช…์ผ ๋•Œ ๋‹น์‹ ์€ ํƒœ์–‘ ์•„๋ž˜ ์žˆ๋Š” ๋ชจ๋“  ๊ฒƒ์— ๋Œ€ํ•ด ์ด์•ผ๊ธฐํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

new LoggableFoo().hello() ๋Š” Greeter๋ฅผ ํ†ตํ•ด ์ž…๋ ฅํ•œ ๋‹ค๋ฅธ ๋ฐฉ๋ฒ•์œผ๋กœ๋Š” ๋„๋‹ฌํ•  ์ˆ˜ ์—†๋Š” ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜๋Š” void ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค.

์ด๊ฒƒ์€ ๋„๋‹ฌํ•  ์ˆ˜ ์—†๋Š” ๊ฒƒ๊ณผ ๋‹ค๋ฆ…๋‹ˆ๋‹ค. ๋„๋‹ฌ ๊ฐ€๋Šฅํ•œ ๋ชจ๋“  ๋ฐฉ๋ฒ•์€ ๋„๋‹ฌ ๊ฐ€๋Šฅํ•œ ๊ฒฝ๋กœ๋ฅผ ํ• ์ธํ•  ๋•Œ "๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด ๋„๋‹ฌํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค".

๋‹น์‹ ์ด ํ–ˆ๋‹ค๋ฉด:

๊ทธ๋Ÿฌ๋‚˜ ์ด๊ฒƒ์€ ๋ง ๊ทธ๋Œ€๋กœ ๋‚ด๊ฐ€ ํ•œ ์ผ์ž…๋‹ˆ๋‹ค. ๊ทธ๊ฒƒ์€ ๋ฐ”๋กœ ๋‚ด๊ฐ€ ๋งŒ๋“  ์˜ˆ์ œ์— ๋Œ€ํ•œ ์„ค๋ช…๊ณผ ํ•จ๊ป˜ ๋‹ค์‹œ ๋ถ™์—ฌ๋„ฃ์€ ๋‚ด ์ฝ”๋“œ ์กฐ๊ฐ์ž…๋‹ˆ๋‹ค. ๋‚˜๋Š” ์‹ฌ์ง€์–ด ๋‚ด๊ฐ€ ๋ฏธ์นœ ์•ฝ์„ ๋จน๊ณ  ์žˆ์ง€ ์•Š์€์ง€ ํ™•์ธํ•˜๊ธฐ ์œ„ํ•ด diff ๊ฒ€์‚ฌ๊ธฐ๋ฅผ ํ†ตํ•ด ์‹คํ–‰ํ–ˆ์œผ๋ฉฐ ์œ ์ผํ•œ ์ฐจ์ด์ ์€ ์ œ๊ฑฐํ•œ ๋Œ“๊ธ€์ž…๋‹ˆ๋‹ค.

๊ทธ๋ฆฌ๊ณ  ๋‹ค์‹œ hello() { return this.foo(); } ๋Š” TypeError๊ฐ€ ์•„๋‹™๋‹ˆ๋‹ค. ์™œ ๊ทธ๋Ÿฐ๊ฐ€์š”?

๋‹น์‹ (๊ทธ๋ฆฌ๊ณ  ์—ฌ๊ธฐ ์žˆ๋Š” ๋‹ค๋ฅธ ์‚ฌ๋žŒ๋“ค)์€ this ์œ ํ˜•์ด ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ์˜ ์ธ์Šคํ„ด์Šคํ™”๋œ ๋ฐ˜ํ™˜ ์œ ํ˜•์ด ๋˜๊ธฐ๋ฅผ ์›ํ•˜๊ธฐ ๋•Œ๋ฌธ์— { hello(): void } ์ž…๋‹ˆ๋‹ค( foo ๋ฉค๋ฒ„๊ฐ€ ์—†์Œ์— ์ฃผ์˜). Foo ์˜ ๋ฉค๋ฒ„๊ฐ€ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ์˜ ๋ฐ˜ํ™˜ ์œ ํ˜•์œผ๋กœ this ๋ฅผ ๋ณผ ์ˆ˜ ์žˆ๊ฒŒ ํ•˜๋ ค๋ฉด hello this ์œ ํ˜•์€ { hello(): void } . { hello(): void } ์ด๋ฉด ์œ ํ˜• ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค. ์œ ํ˜• ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•˜๋ฉด ๋‚ด ์ฝ”๋“œ๊ฐ€ ์ œ๋Œ€๋กœ ์‹คํ–‰๋˜๊ธฐ ๋•Œ๋ฌธ์— ์Šฌํ”•๋‹ˆ๋‹ค.

์œ ํ˜• ์˜ค๋ฅ˜๊ฐ€ ์•„๋‹ˆ๋ผ๊ณ  ๋งํ•˜๋ฉด ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ์˜ ๋ฐ˜ํ™˜ ์œ ํ˜•์„ ํ†ตํ•ด this ์œ ํ˜•์„ ์ œ๊ณตํ•˜๋Š” ์ž์ฒด ์ฒด๊ณ„๋ฅผ ํฌ๊ธฐํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. this ์˜ ์œ ํ˜•์€ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๊ฐ€ ๋ฐ˜ํ™˜ํ•˜๋Š” ๊ฒƒ๊ณผ ์ƒ๊ด€์—†์ด { hello(): string; bar(): string } ์ž…๋‹ˆ๋‹ค. ์ด ๋ฌธ์ œ๋ฅผ ๋ฐฉ์ง€ํ•˜๊ธฐ this ์œ ํ˜•์„ ์ƒ์„ฑํ•˜๊ธฐ ์œ„ํ•œ ๋ช‡ ๊ฐ€์ง€ ๋Œ€์ฒด ์ฒด๊ณ„๊ฐ€ ์žˆ์„ ์ˆ˜ ์žˆ์ง€๋งŒ ๊ทธ๊ฒƒ์ด ๋ฌด์—‡์ธ์ง€ ์ง€์ •ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๊ฐ€ ์‹คํ–‰๋œ ํ›„ Foo ๊ฐ€ ์›๋ž˜ ์ •์˜๋œ ๊ฒƒ๊ณผ ์™„์ „ํžˆ ๋‹ค๋ฅธ ๊ฒƒ์„ ์ฐธ์กฐํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์„ ์ดํ•ดํ•˜์ง€ ๋ชปํ•˜๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

function a(C){
    return class {
        x(){}
        y(){}
        z(){}
    }
}

<strong i="7">@a</strong>
class Foo {
    a(){ 
        this.b();  //valid
    }
    b() { 
        this.c();  //also valid
    }
    c(){ 
        return 0;
    }
}

let f = new Foo();
f.x(); //valid
f.y(); //also valid
f.z(); //still valid

this ๊ฐ€ ์œ„์˜ Foo ๋‚ด๋ถ€์—์„œ ๋ญ”๊ฐ€ ๋‹ค๋ฅธ ๊ฒƒ์ด ์žˆ๋‹ค๋Š” ์ ์—์„œ ์ด์ƒํ•œ ์ ์„ ๋ฐœ๊ฒฌํ–ˆ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค Foo ๊ฐ€ (๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๊ฐ€ ์‹คํ–‰๋œ ํ›„) ๊ฒฐ๊ณผ์ ์œผ๋กœ ์ƒ์„ฑ๋˜๋Š” ๊ฒฝ์šฐ์™€๋Š” ๋‹ค๋ฆ…๋‹ˆ๋‹ค.

๋ฌด์—‡์„ ๋งํ•ด์•ผ ํ• ์ง€ ์ž˜ ๋ชจ๋ฅด๊ฒ ์Šต๋‹ˆ๋‹ค. ๊ทธ๊ฒƒ์ด ๋ฐ”๋กœ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๊ฐ€ ์ž‘๋™ํ•˜๋Š” ๋ฐฉ์‹์ž…๋‹ˆ๋‹ค. ๋‚ด ์œ ์ผํ•œ ์ฃผ์žฅ์€ TypeScript๊ฐ€ ๋ฌด์Šจ ์ผ์ด ์ผ์–ด๋‚˜๊ณ  ์žˆ๋Š”์ง€ ๋” ๋ฐ€์ ‘ํ•˜๊ฒŒ ์ผ์น˜ํ•ด์•ผ ํ•œ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๋‹ค์‹œ ๋งํ•ด, (์›๋ž˜) Foo ๋‚ด๋ถ€์˜ ์œ ํ˜• ์„œ๋ช…์€ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๊ฐ€ ์‹คํ–‰๋˜๋ฉด Foo๊ฐ€ ์ƒ์„ฑํ•˜๋Š” ๊ฒƒ๊ณผ ๋‹ค๋ฆ…๋‹ˆ๋‹ค.

๋‹ค๋ฅธ ์–ธ์–ด์—์„œ ๋น„์œ ๋ฅผ ๋นŒ๋ฆฌ์ž๋ฉด ์žฅ์‹๋œ Foo ๋‚ด๋ถ€์—์„œ ์ด๊ฒƒ์€ C# ์ต๋ช… ์œ ํ˜•์— ํ•ด๋‹นํ•˜๋Š” ๊ฒƒ์„ ์ฐธ์กฐํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์™„์ „ํžˆ ์‹ค์ œ ์œ ํ˜•์ž…๋‹ˆ๋‹ค. ๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด ์œ ํšจํ•˜์ง€๋งŒ ์‹ค์ œ๋กœ ์ง์ ‘ ์ฐธ์กฐํ•  ์ˆ˜๋Š” ์—†์Šต๋‹ˆ๋‹ค. ์œ„์—์„œ ์„ค๋ช…ํ•œ ์˜ค๋ฅ˜ ๋ฐ ๋น„ ์˜ค๋ฅ˜๋ฅผ ์–ป๋Š” ๊ฒƒ์ด ์ด์ƒํ•˜๊ฒŒ ๋ณด์ผ ์ˆ˜ ์žˆ์ง€๋งŒ ๋‹ค์‹œ ๋งํ•˜์ง€๋งŒ ๊ทธ๊ฒƒ์ด ์ž‘๋™ํ•˜๋Š” ๋ฐฉ์‹์ž…๋‹ˆ๋‹ค. ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋Š” ์šฐ๋ฆฌ์—๊ฒŒ ์ด์™€ ๊ฐ™์€ ๊ธฐ์ดํ•œ ์ผ์„ ํ•  ์ˆ˜ ์žˆ๋Š” ์—„์ฒญ๋‚œ ํž˜์„ ์ค๋‹ˆ๋‹ค.

์œ„์˜ Foo ๋‚ด๋ถ€์—์„œ ๋ญ”๊ฐ€ ๋‹ค๋ฅธ ๊ฒƒ์ด ์žˆ๋‹ค๋Š” ์ ์—์„œ ์ด์ƒํ•œ ์ ์„ ๋ฐœ๊ฒฌํ–ˆ๋‹ค๊ณ  ์ถ”์ธกํ•ฉ๋‹ˆ๋‹ค. (๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๊ฐ€ ์‹คํ–‰๋œ ํ›„) Foo์—์„œ ๊ฒฐ๊ณผ์ ์œผ๋กœ ์ƒ์„ฑ๋˜๋Š” ๊ฒฝ์šฐ์™€ ๋‹ค๋ฆ…๋‹ˆ๋‹ค.

์•„๋‹ˆ์˜ค. ์ €๋Š” ๊ฑฐ๊ธฐ์—์„œ ์ด์ƒํ•œ ์ ์„ ์ฐพ์ง€ ๋ชปํ–ˆ์Šต๋‹ˆ๋‹ค. ์™œ๋ƒํ•˜๋ฉด ๊ทธ๊ฒƒ์€ ์ œ๊ฐ€ 200๊ฐœ์˜ ๋Œ“๊ธ€์„ ์ „์— ์ œ์•ˆํ–ˆ๋˜ ๊ฒƒ๊ณผ ์ •ํ™•ํžˆ ์ผ์น˜ํ•˜๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ๋‹น์‹ ์€ ์•ž์˜ ํ† ๋ก ์„ ์ฝ์—ˆ์Šต๋‹ˆ๊นŒ?

๊ท€ํ•˜๊ฐ€ ๊ฒŒ์‹œํ•œ ์Šค๋‹ˆํŽซ์€ ์ „ํ˜€ ๋…ผ๋ž€์˜ ์—ฌ์ง€๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. ๋‚ด๊ฐ€ ๋™์˜ํ•˜์ง€ ์•Š๋Š” ์‚ฌ๋žŒ๋“ค๊ณผ ๋‹น์‹ ์ด ๋„์›€์„ ์š”์ฒญํ•œ ์‚ฌ๋žŒ๋“ค์€ ์ถ”๊ฐ€ ๋กœ ๋‹ค์Œ์„ ์›ํ•ฉ๋‹ˆ๋‹ค.

function a(C){
    return class {
        x(){}
        y(){}
        z(){}
    }
}

<strong i="10">@a</strong>
class Foo {
    a(){ 
        this.b();  //valid
    }
    b() { 
        this.c();  //also valid
    }
    c(){ 
        return 0;
    }
    d(){
        // HERE: All of these are also expected to be valid
        this.x();
        this.y();
        this.z();
    }
}

let f = new Foo();
f.x(); //valid
f.y(); //also valid
f.z(); //still valid

๋‚˜๋Š” ์ด๊ฒƒ์„ ๊ฑด์ „ํ•˜๊ฒŒ ํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ๋ฐ ๋™์˜ํ•˜์ง€ ์•Š์œผ๋ฉฐ ๊ทธ๋Ÿฌํ•œ ์ œ์•ˆ์ด ์–ด๋–ป๊ฒŒ ์ž‘๋™ํ•˜๋Š”์ง€ ์•Œ์•„ ๋‚ด๋ ค๊ณ  ํ•„์‚ฌ์ ์œผ๋กœ ๋…ธ๋ ฅํ–ˆ์Šต๋‹ˆ๋‹ค. ์ตœ์„ ์˜ ๋…ธ๋ ฅ์—๋„ ๋ถˆ๊ตฌํ•˜๊ณ  this ์ด(๊ฐ€) ๊ฐ€์งˆ ๊ฒƒ์œผ๋กœ ์˜ˆ์ƒ๋˜๋Š” ํšŒ์›์˜ ์ „์ฒด ๋ชฉ๋ก์ด๋‚˜ ์ด๋Ÿฌํ•œ ๋ชฉ๋ก์ด ์ œ์•ˆ์„œ์— ๋”ฐ๋ผ ๊ตฌ์„ฑ๋˜๋Š” ๋ฐฉ์‹์„ ์ถ”์ถœํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

๋‹ค์‹œ ๋งํ•ด, (์›๋ž˜) Foo ๋‚ด๋ถ€์˜ ์œ ํ˜• ์„œ๋ช…์€ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๊ฐ€ ์‹คํ–‰๋˜๋ฉด Foo๊ฐ€ ์ƒ์„ฑํ•˜๋Š” ๊ฒƒ๊ณผ ๋‹ค๋ฆ…๋‹ˆ๋‹ค.

๊ทธ๋Ÿฐ๋ฐ๋„ ์™œ ๋‚˜์™€ ๋ง๋‹คํˆผ์„ ํ•˜๋Š๋ƒ? ๋‚˜๋Š” ๋งํ–ˆ๋‹ค: "๋‚˜๋Š” new Foo().foo๊ฐ€ ํƒ€์ž… ์—๋Ÿฌ๊ฐ€ ๋˜๋Š” ๊ฒƒ์ด ๋ฒ„๊ทธ๋ผ๋Š” ๊ฒƒ์— ๋™์˜ํ•˜๊ณ , ๊ทธ๊ฒƒ์— ๋Œ€ํ•ด ์‰ฝ๊ฒŒ ๊ณ ์น  ์ˆ˜ ์žˆ๋‹ค. ๋‚˜๋Š” this.foo๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค๋Š” ๊ฒƒ์— ๋™์˜ํ•˜์ง€ ์•Š๋Š”๋‹ค. ํƒ€์ž… ์—๋Ÿฌ๊ฐ€ ๋˜๋Š” ๊ฒƒ์€ ๋ฒ„๊ทธ์ด๋‹ค." ์œ ์‚ฌํ•˜๊ฒŒ, ๊ท€ํ•˜์˜ ์˜ˆ์—์„œ new Foo().x() ๊ฐ€ ์œ ํ˜• ์˜ค๋ฅ˜์ธ ๊ฒƒ์€ ๋ฒ„๊ทธ์ด์ง€๋งŒ this.x() ์ธ ์œ ํ˜• ์˜ค๋ฅ˜๋Š” ๊ทธ๋ ‡์ง€ ์•Š๋‹ค๋Š” ๋ฐ ๋™์˜ํ•ฉ๋‹ˆ๋‹ค.

์ด ํŽ˜์ด์ง€ ์ƒ๋‹จ์˜ ์Šค๋‹ˆํŽซ์— ๋‘ ๊ฐœ์˜ ๋Œ“๊ธ€์ด ์žˆ๋Š” ๊ฒƒ์„ ๋ณด์…จ์Šต๋‹ˆ๊นŒ?

        return this.foo; // Property 'foo' does not exist on type 'Foo'

^^ ์ œ๊ฐ€ ๋ฌธ์ œ๋ผ๊ณ  ์ƒ๊ฐํ•˜๋Š” ๋ถ€๋ถ„์ž…๋‹ˆ๋‹ค. ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ์˜ ๋ฐ˜ํ™˜ ์œ ํ˜•์ด this ์— ํ‘œ์‹œ๋˜์–ด์„œ๋Š” ์•ˆ ๋˜๋ฉฐ $ new Foo() ์—๋งŒ ํ‘œ์‹œ๋˜์–ด์•ผ ํ•œ๋‹ค๋Š” ๋ฐ ๋™์˜ํ•ฉ๋‹ˆ๋‹ค. ๋˜๋Š” ๋™์˜ํ•˜์ง€ ์•Š๊ณ  ํ•ด๋‹น ๊ธฐ๋Šฅ๋„ ์›ํ•ฉ๋‹ˆ๋‹ค. ์ด ๊ฒฝ์šฐ ์ด์ „ ๋Œ“๊ธ€์˜ ์Šค๋‹ˆํŽซ์€ ๊ด€๋ จ์ด ์—†์Šต๋‹ˆ๋‹ค.

๋‚˜๋Š” ๋งˆ์นจ๋‚ด ๋‹น์‹ ์˜ ์š”์ ์„ ์ดํ•ดํ•ฉ๋‹ˆ๋‹ค. ๊ท€ํ•˜์˜ Greeter ์ฝ”๋“œ์—์„œ ์ด๊ฒƒ์„ ์–ป๋Š” ๊ฒƒ์ด ๋งค์šฐ ์–ด๋ ค์› ์ง€๋งŒ ์ง€๊ธˆ ์ถ”์  ์ค‘์ž…๋‹ˆ๋‹ค. ์ธ๋‚ดํ•ด์ฃผ์…”์„œ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค.

์œ ์ผํ•œ ํ•ฉ๋ฆฌ์ ์ธ ํ•ด๊ฒฐ์ฑ…์€ Foo(Foo ๋‚ด๋ถ€ )๊ฐ€ ์›๋ž˜ Foo์˜ ์œ ํ˜• ๊ฒฐํ•ฉ(derp๋Š” ๊ต์ง‘ํ•ฉ์„ ์˜๋ฏธํ•จ)๊ณผ ๋งˆ์ง€๋ง‰ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๊ฐ€ ๋ฐ˜ํ™˜ํ•˜๋Š” ๋ชจ๋“  ๊ฒƒ์„ ์ง€์›ํ•˜๋Š” ๊ฒƒ์ด๋ผ๊ณ  ๋งํ•˜๊ณ  ์‹ถ์Šต๋‹ˆ๋‹ค. Greeter์™€ ๊ฐ™์€ ๋ฏธ์นœ ์˜ˆ์ œ์˜ ๊ฒฝ์šฐ ์›๋ž˜ Foo ๋ฅผ ์ง€์›ํ•ด์•ผ ํ•˜๋ฉฐ, ๋งˆ์ง€๋ง‰ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ ๊ฐ€ ๋ฐ˜ํ™˜ํ•˜๋Š” ๋ชจ๋“  ๊ฒƒ์„ ์ง€์›ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ด๊ฒƒ์ด ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์š”์  ์ด๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค(์œ„์˜ ๋งŽ์€ ์„ค๋ช…์— ๋”ฐ๋ผ).

์˜ˆ, ๊ฐ€์žฅ ์ตœ๊ทผ์˜ ์˜ˆ์—์„œ Foo x, y, z, a, b, c ๋‚ด๋ถ€์—์„œ ๋ชจ๋‘ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค. a ์˜ ๋‘ ๊ฐ€์ง€ ๋ฒ„์ „์ด ์žˆ๋Š” ๊ฒฝ์šฐ ๋‘˜ ๋‹ค ์ง€์›ํ•ฉ๋‹ˆ๋‹ค.

@arackaf np๋‹˜๋„ ๊ธฐ๋‹ค๋ ค์ฃผ์…”์„œ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค. ๋‚ด ์˜ˆ์ œ๊ฐ€ ๊ฐ€์žฅ ๋ช…ํ™•ํ•˜์ง€ ์•Š์€ ์ด์œ ๋Š” ๋†€์ดํ„ฐ์—์„œ ๋‚ด๊ฐ€ ์š”๋ฆฌํ•  ์ˆ˜ ์žˆ๋Š” ๋ชจ๋“  ๊ฒƒ์„ ๊ฒŒ์‹œํ•˜์—ฌ ๊ณ ์žฅ๋‚œ ๋ฐฉ๋ฒ•์„ ๋ณด์—ฌ์ฃผ๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ์ฒด๊ณ„์ ์œผ๋กœ ์ƒ๊ฐํ•˜๊ธฐ ์–ด๋ ต๋„ค์š”.

์œ ์ผํ•œ ํ•ฉ๋ฆฌ์ ์ธ ํ•ด๊ฒฐ์ฑ…์€ Foo(Foo ๋‚ด๋ถ€)๊ฐ€ ์›๋ž˜ Foo์˜ ์œ ํ˜• ํ•ฉ์ง‘ํ•ฉ๊ณผ ๋งˆ์ง€๋ง‰ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๊ฐ€ ๋ฐ˜ํ™˜ํ•˜๋Š” ๋ชจ๋“  ๊ฒƒ์„ ์ง€์›ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์ข‹์Šต๋‹ˆ๋‹ค. ์ด์ œ ์„ธ๋ถ€ ์‚ฌํ•ญ์— ๋Œ€ํ•ด ์•Œ์•„๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. ๋‚ด๊ฐ€ ์ด๊ฒƒ์„ ์ž˜๋ชป ์ดํ•ดํ•˜๊ณ  ์žˆ๋‹ค๋ฉด ์ €๋ฅผ ์ˆ˜์ •ํ•˜์‹ญ์‹œ์˜ค. ๊ทธ๋Ÿฌ๋‚˜ "union"์ด๋ผ๊ณ  ๋งํ•˜๋ฉด ๋‘˜ ๋‹ค์˜ ์œ ํ˜• ๋ฉค๋ฒ„๊ฐ€ ์žˆ์–ด์•ผ ํ•จ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค. ์ฆ‰, A & B ์ด์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ ์šฐ๋ฆฌ๋Š” this ๊ฐ€ typeof(new OriginalClass()) & typeof(new (decorators(OriginalClass))) ๊ฐ€ ๋˜๊ธฐ๋ฅผ ์›ํ•ฉ๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์„œ decorators ๋Š” ๋ชจ๋“  ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ์˜ ํ•ฉ์„ฑ ์œ ํ˜• ์„œ๋ช…์ž…๋‹ˆ๋‹ค. ์ผ๋ฐ˜ ์˜์–ด์—์„œ ์šฐ๋ฆฌ๋Š” this ๊ฐ€ "์›๋ž˜ ํด๋ž˜์Šค"์˜ ์ธ์Šคํ„ด์Šคํ™”๋œ ์œ ํ˜•๊ณผ ๋ชจ๋“  ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋ฅผ ํ†ต๊ณผํ•œ "์›๋ณธ ํด๋ž˜์Šค"์˜ ์ธ์Šคํ„ด์Šคํ™”๋œ ์œ ํ˜•์˜ ๊ต์ฐจ์ ์ด ๋˜๊ธฐ๋ฅผ ์›ํ•ฉ๋‹ˆ๋‹ค.

์—ฌ๊ธฐ์—๋Š” ๋‘ ๊ฐ€์ง€ ๋ฌธ์ œ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ํ•˜๋‚˜๋Š” ๋‚ด ์˜ˆ์™€ ๊ฐ™์€ ๊ฒฝ์šฐ ์กด์žฌํ•˜์ง€ ์•Š๋Š” ๋ฉค๋ฒ„์— ์•ก์„ธ์Šคํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ์— ๋งŽ์€ ๋ฉค๋ฒ„๋ฅผ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ์ง€๋งŒ this.newMethod() ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํด๋ž˜์Šค์—์„œ ๋ฉค๋ฒ„์— ์•ก์„ธ์Šคํ•˜๋ ค๊ณ  ํ•˜๋ฉด ๋Ÿฐํƒ€์ž„์— ํ† ํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค. newMethod ๋Š” ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ ํ•จ์ˆ˜์—์„œ ๋ฐ˜ํ™˜๋œ ํด๋ž˜์Šค์—๋งŒ ์ถ”๊ฐ€๋˜๋ฉฐ ์›๋ž˜ ํด๋ž˜์Šค์˜ ๋ฉค๋ฒ„๋Š” ์•ก์„ธ์Šคํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค(ํŠน๋ณ„ํžˆ return class extends OriginalClass { newMethod() { } } ํŒจํ„ด์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” ํ•œ).

๋‹ค๋ฅธ ๋ฌธ์ œ๋Š” "์›๋ž˜ ํด๋ž˜์Šค"๊ฐ€ ์ž˜ ์ •์˜๋œ ๊ฐœ๋…์ด ์•„๋‹ˆ๋ผ๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. this ์—์„œ ๋ฐ์ฝ”๋ ˆ์ดํŠธ๋œ ๋ฉค๋ฒ„์— ์•ก์„ธ์Šค ํ•  ์ˆ˜ ์žˆ๋‹ค๋ฉด return ๋ฌธ์˜ ์ผ๋ถ€๋กœ ์‚ฌ์šฉํ•  ์ˆ˜๋„ ์žˆ์œผ๋ฏ€๋กœ "์›๋ž˜ ํด๋ž˜์Šค"์˜ ๊ณต๊ฐœ API์˜ ์ผ๋ถ€์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ €๋Š” ์—ฌ๊ธฐ์—์„œ ์†์„ ํ”๋“œ๋Š” ํŽธ์ด๋ผ ๊ตฌ์ฒด์ ์ธ ์˜ˆ๋ฅผ ์ƒ๊ฐํ•˜๊ธฐ์—๋Š” ๋„ˆ๋ฌด ์ง€์ณ์žˆ์ง€๋งŒ, ๊ณฐ๊ณฐ์ด ์ƒ๊ฐํ•ด๋ณด๋ฉด ๋ง๋„ ์•ˆ ๋˜๋Š” ์˜ˆ๊ฐ€ ๋‚˜์˜ฌ ์ˆ˜ ์žˆ์„ ๊ฒƒ ๊ฐ™์•„์š”. this ์—์„œ ์•ก์„ธ์Šคํ•œ ํ•ญ๋ชฉ์„ ๋ฐ˜ํ™˜ํ•˜์ง€ ์•Š๊ฑฐ๋‚˜ ์ตœ์†Œํ•œ this.something() ์„ ๋ฐ˜ํ™˜ํ•œ ๊ฒฐ๊ณผ ๋ฐ˜ํ™˜ ์œ ํ˜•์ด ์œ ์ถ”๋˜์ง€ ์•Š์€ ๊ตฌ์„ฑ์›์„ ๋ถ„๋ฆฌํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์ฐพ์•„ ์ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

@masaeedu ๋„ค, ๋‹ต๋ณ€ ์ „์— ์—ฐํ•ฉ/๊ต์ฐจ ๋ถ€๋ถ„์— ๋Œ€ํ•ด ์ˆ˜์ •ํ–ˆ์Šต๋‹ˆ๋‹ค. TS๋ฅผ ์ฒ˜์Œ ์ ‘ํ•˜๋Š” ์‚ฌ๋žŒ์—๊ฒŒ๋Š” ์ง๊ด€์ ์ด์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

๋‚˜๋จธ์ง€๋Š” ์ดํ•ดํ–ˆ์Šต๋‹ˆ๋‹ค. ์†”์งํžˆ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋Š” ์ผ๋ฐ˜์ ์œผ๋กœ ์™„์ „ํžˆ ๋‹ค๋ฅธ ์œ ํ˜•์„ ๋ฐ˜ํ™˜ํ•˜์ง€ ์•Š๊ณ  ์ผ๋ฐ˜์  ์œผ๋กœ ์ „๋‹ฌ๋œ ์œ ํ˜•์„ ๋ณด๊ฐ•ํ•˜๋ฏ€๋กœ ๋Œ€๋ถ€๋ถ„์˜ ๊ฒฝ์šฐ ๊ต์ฐจ๋กœ๊ฐ€ ์•ˆ์ „ํ•˜๊ฒŒ "๊ทธ๋ƒฅ ์ž‘๋™"ํ•ฉ๋‹ˆ๋‹ค.

๋‚˜๋Š” ๋‹น์‹ ์ด ๋งํ•˜๋Š” ๋Ÿฐํƒ€์ž„ ์˜ค๋ฅ˜๊ฐ€ ๋“œ๋ฌผ๊ณ  ์˜๋„์ ์œผ๋กœ ์ž˜๋ชป๋œ ๊ฐœ๋ฐœ ๊ฒฐ์ •์˜ ๊ฒฐ๊ณผ๋ผ๊ณ  ๋งํ•˜๊ณ  ์‹ถ์Šต๋‹ˆ๋‹ค. ๋‚˜๋Š” ๋‹น์‹ ์ด ์ด๊ฒƒ์— ๋Œ€ํ•ด ์ •๋ง๋กœ ์‹ ๊ฒฝ์จ์•ผ ํ•˜๋Š”์ง€ ํ™•์‹ ํ•˜์ง€ ๋ชปํ•˜์ง€๋งŒ, ๊ทธ๊ฒƒ์ด ์ •๋ง๋กœ ๋ฌธ์ œ๋ผ๋ฉด, ๋‚˜๋Š” ๋งˆ์ง€๋ง‰ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๊ฐ€ ๋ฐ˜ํ™˜ํ•œ ๊ฒƒ์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ๊ดœ์ฐฎ์€ ๋‘ ๋ฒˆ์งธ ์žฅ์†Œ๊ฐ€ ๋  ๊ฒƒ์ด๋ผ๊ณ  ๋งํ•˜๊ณ  ์‹ถ์Šต๋‹ˆ๋‹ค. (๊ทธ๋ž˜์„œ, ํด๋ž˜์Šค๋Š” ์ž์ฒด์ ์œผ๋กœ ์ •์˜ํ•œ ๋ฐฉ๋ฒ•์„ ์‚ฌ์šฉํ•˜๋ ค๊ณ  ํ•ฉ๋‹ˆ๋‹ค. ์ด์ƒ์ ์ด์ง€๋Š” ์•Š์ง€๋งŒ ์ž‘์—…ํ•˜๋Š” ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ์— ๋Œ€ํ•ด ์ง€๋ถˆํ•  ๊ฐ€์น˜๊ฐ€ ์žˆ๋Š” ๊ฐ€๊ฒฉ).

๊ทธ๋Ÿฌ๋‚˜ ์‹ค์ œ๋กœ, ๋‚˜๋Š” ๋‹น์‹ ์ด ์ƒ๊ฐํ•˜๊ณ  ์žˆ๋Š” ๋Ÿฐํƒ€์ž„ ์˜ค๋ฅ˜๊ฐ€ ์˜ˆ๋ฐฉํ•  ๊ฐ€์น˜๊ฐ€ ์—†๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ํ™•์‹คํžˆ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๊ฐ€ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์ž‘๋™ํ•˜๋Š” ๊ฒƒ์„ ํฌ์ƒ์‹œํ‚ค๋ฉด์„œ ๋ง์ด์ฃ . ๊ฒŒ๋‹ค๊ฐ€, ๋ถ€์ฃผ์˜ํ•˜๊ฑฐ๋‚˜ ์–ด๋ฆฌ์„์€ ๊ฒฝ์šฐ TS์—์„œ ๋Ÿฐํƒ€์ž„ ์˜ค๋ฅ˜๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๊ฒƒ์€ ๋งค์šฐ ์‰ฝ์Šต๋‹ˆ๋‹ค.

interface C { a(); }
class C {
    foo() {
        this.a();  //<--- boom
    }
}

let c = new C();
c.foo();

๋‘ ๋ฒˆ์งธ ์ด์˜ ์ œ๊ธฐ์— ๋Œ€ํ•ด

๋˜ํ•œ return ๋ฌธ์˜ ์ผ๋ถ€๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ "์›๋ž˜ ํด๋ž˜์Šค"์˜ ๊ณต๊ฐœ API์˜ ์ผ๋ถ€์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋‚˜๋Š” ๊ทธ๊ฒƒ์— ๋Œ€ํ•ด ์•„๋ฌด๋Ÿฐ ๋ฌธ์ œ๊ฐ€ ์—†๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ๋‚˜๋Š” ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋ฅผ ํ†ตํ•ด ํด๋ž˜์Šค์— ์ถ”๊ฐ€๋œ ๋ชจ๋“  ๊ฒƒ์ด ์ ˆ๋Œ€์ ์œผ๋กœ ์ผ๋ฅ˜ ์‹œ๋ฏผ ์ด ๋˜๊ธฐ๋ฅผ ์›ํ•ฉ๋‹ˆ๋‹ค . ์–ด๋–ค ์ž ์žฌ์ ์ธ ๋ฌธ์ œ๊ฐ€ ์žˆ์„์ง€ ๊ถ๊ธˆํ•ฉ๋‹ˆ๋‹ค.

๋‹ค๋ฅธ ์ข‹์€ ์˜ต์…˜ ์ค‘ ํ•˜๋‚˜๋Š” ์ด๊ฒƒ์„ ๋ถ€๋ถ„์ ์œผ๋กœ๋งŒ ๊ตฌํ˜„ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

ํ˜„์žฌ ํด๋ž˜์Šค๋Š” ํ•ญ์ƒ ์ •์˜๋œ ๋Œ€๋กœ ์œ ํ˜•์ด ์ง€์ •๋ฉ๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ Foo ๋‚ด๋ถ€์—์„œ๋Š” ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ์— ๊ด€๊ณ„์—†์ด foo๊ฐ€ ์ •์˜๋œ ๋ฐฉ์‹์„ ๊ธฐ๋ฐ˜์œผ๋กœ ํ•ฉ๋‹ˆ๋‹ค. ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ ์‚ฌ์šฉ ์‚ฌ๋ก€์˜ ์ผ๋ถ€ ์œ ์šฉํ•œ ํ•˜์œ„ ์ง‘ํ•ฉ(์ฆ‰, ๊ฐ€์žฅ ์ผ๋ฐ˜์ ์ธ ๊ฒฝ์šฐ)์— ๋Œ€ํ•ด "๊ทธ๋ƒฅ" ํ™•์žฅํ•˜๋Š” ๊ฒƒ์€ ์—„์ฒญ๋‚˜๊ฒŒ ํฐ ๊ฐœ์„ ์ด ๋  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๊ฐ€ ์›๋ณธ์„ ํ™•์žฅํ•˜๋Š” ๊ฒƒ์„ ๋ฐ˜ํ™˜ํ•˜๋Š” ๊ฒฝ์šฐ์—๋งŒ(ํด๋ž˜์Šค ๋‚ด๋ถ€์˜ this ๊ด€์ ์—์„œ) ํด๋ž˜์Šค ํ™•์žฅ์„ ํ—ˆ์šฉํ•˜๋ฉด ์–ด๋–ป๊ฒŒ ๋ ๊นŒ์š”?

function d(Class) {
    return class extends Class {
        blah() { }
    };
}

<strong i="9">@d</strong>
class Foo {
    a() { }
    b() { }
    c() { 
        this.blah(); // <---- valid
    }
}

๊ทธ๋ƒฅ ์ž‘๋™ํ•˜๊ฒŒ ํ•˜๊ณ  blah ๋ฐ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๊ฐ€ ์ถ”๊ฐ€ํ•œ ๋ชจ๋“  ๊ฒƒ์— ๋Œ€ํ•ด ์ตœ๊ณ  ์ˆ˜์ค€์˜ ์ง€์›์„ ์ œ๊ณตํ•˜์‹ญ์‹œ์˜ค. ๊ทธ๋ฆฌ๊ณ  ์™„์ „ํžˆ ์ƒˆ๋กœ์šด ํด๋ž˜์Šค(์˜ˆ: Greeter)๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ๊ฒƒ๊ณผ ๊ฐ™์€ ๋ฏธ์นœ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๋Š” ์‚ฌ์šฉ ์‚ฌ๋ก€์˜ ๊ฒฝ์šฐ ํ˜„์žฌ ๋™์ž‘์„ ๊ณ„์†ํ•˜๊ณ  ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๊ฐ€ ์ˆ˜ํ–‰ํ•˜๋Š” ์ž‘์—…์„ ๋ฌด์‹œํ•ฉ๋‹ˆ๋‹ค.


Btw, ๋‹น์‹ ์ด ๋ฌด์—‡์„ ์„ ํƒํ•˜๋“  ์ƒ๊ด€์—†์ด ์–ด๋–ป๊ฒŒ ์ฃผ์„์„ ๋‹ฌ๊ฒ ์Šต๋‹ˆ๊นŒ? ํ˜„์žฌ ์ฃผ์„์„ ๋‹ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ? ๋‚˜๋Š” ์‹œ๋„ํ–ˆ๋‹ค

function d<T>(Class: new() => T): T & { new (): { blah(): void } } {
    return class extends Class {
        blah() { }
    };
}

๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ํ•ด๋‹น ํ…Œ๋งˆ์— ๋Œ€ํ•œ ๋งŽ์€ ๋ณ€ํ˜•์ด ์žˆ์ง€๋งŒ TypeScript์—๋Š” ์•„๋ฌด ๊ฒƒ๋„ ์—†์—ˆ์Šต๋‹ˆ๋‹ค. :)

@arackaf ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋Š” ํ•จ์ˆ˜์ผ ๋ฟ์ž…๋‹ˆ๋‹ค. ์ผ๋ฐ˜์ ์ธ ๊ฒฝ์šฐ ์–ด๋”˜๊ฐ€์— .d.ts ํŒŒ์ผ์—์„œ ๊ฐ€์ ธ์˜ค๊ณ  ๊ตฌํ˜„ ๋ฐฉ๋ฒ•์„ ๋ชจ๋ฆ…๋‹ˆ๋‹ค. ๊ตฌํ˜„์ด ์™„์ „ํžˆ ์ƒˆ๋กœ์šด ํด๋ž˜์Šค๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š”์ง€, ์›๋ž˜ ํด๋ž˜์Šค์˜ ํ”„๋กœํ† ํƒ€์ž…์—์„œ ๋ฉค๋ฒ„๋ฅผ ์ถ”๊ฐ€/๋นผ๊ธฐ/๊ต์ฒดํ•˜๊ณ  ๋ฐ˜ํ™˜ํ•˜๋Š”์ง€ ๋˜๋Š” ์›๋ž˜ ํด๋ž˜์Šค๋ฅผ ํ™•์žฅํ•˜๋Š”์ง€ ์•Œ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์€ ํ•จ์ˆ˜์˜ ๊ตฌ์กฐ์  ๋ฐ˜ํ™˜ ์œ ํ˜•๋ฟ์ž…๋‹ˆ๋‹ค.

์–ด๋–ป๊ฒŒ๋“  ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋ฅผ ํด๋ž˜์Šค ์ƒ์†์— ๋ฌถ๊ณ  ์‹ถ๋‹ค๋ฉด ๋จผ์ € JS์— ๋Œ€ํ•œ ๋ณ„๋„์˜ ์–ธ์–ด ๊ฐœ๋…์„ ์ œ์•ˆํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์˜ค๋Š˜๋‚  ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๊ฐ€ ์ž‘๋™ํ•˜๋Š” ๋ฐฉ์‹์€ ์ผ๋ฐ˜์ ์ธ ๊ฒฝ์šฐ this ๋ฅผ ๋ณ€๊ฒฝํ•˜๋Š” ๊ฒƒ์„ ์ •๋‹นํ™”ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, ์ €๋Š” ๊ฐœ์ธ์ ์œผ๋กœ ํ•ญ์ƒ ์ƒ์†๋ณด๋‹ค ๊ตฌ์„ฑ์„ ์„ ํ˜ธํ•˜๋ฉฐ ํ•ญ์ƒ ๋‹ค์Œ์„ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค.

function logger<T extends Constructor<Greeter>>(Class: T) {
    return class {
        readonly _impl;
        constructor() {
            this._impl = new Class()
        }
        // Use _impl ...
    };
}

์ด๊ฒƒ์€ ๋ฏธ์นœ ํ•™๋ฌธ์  ์‹คํ—˜์ด ์•„๋‹™๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ ๋ฏน์Šค์ธ์„ ์ˆ˜ํ–‰ํ•˜๊ธฐ ์œ„ํ•œ ๋Šช์ง€ ํ‘œ์ค€ ์ ‘๊ทผ ๋ฐฉ์‹์ด๋ฉฐ, ์ œ๊ฐ€ ์—ฌ๋Ÿฌ๋ถ„์—๊ฒŒ ์ œ๊ณตํ•œ ์˜ˆ๋ฅผ ๊นฌ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์‚ฌ์‹ค return class extends Class ๋ฅผ ์ œ์™ธํ•œ ๊ฑฐ์˜ ๋ชจ๋“  ๊ฒƒ์€ ๋‚ด๊ฐ€ ์—ฌ๋Ÿฌ๋ถ„์—๊ฒŒ ์ œ๊ณตํ•œ ์˜ˆ์ œ์™€ ์ค‘๋‹จ ๋˜๋ฉฐ ๋งŽ์€ ๊ฒฝ์šฐ return class extends Class ๋กœ ์ค‘๋‹จ๋ฉ๋‹ˆ๋‹ค.

์ด ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๋ ค๋ฉด ๋ชจ๋“  ์ข…๋ฅ˜์˜ ๊ณ ๋ฆฌ์™€ ๋น„ํ‹€๋ฆผ์„ ํ†ต๊ณผํ•ด์•ผ ํ•˜๊ณ  ์œ ํ˜• ์‹œ์Šคํ…œ์€ ๋ชจ๋“  ๋‹จ๊ณ„์—์„œ ๋‹น์‹ ๊ณผ ์‹ธ์šธ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์™œ๋ƒํ•˜๋ฉด ๋‹น์‹ ์ด ํ•˜๋Š” ์ผ์ด ์ผ๋ฐ˜์ ์ธ ๊ฒฝ์šฐ์— ๋ฌด์˜๋ฏธํ•˜๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ๋” ์ค‘์š”ํ•œ ๊ฒƒ์€ ์ผ๋‹จ ๊ตฌํ˜„ํ•˜๋ฉด ๋ชจ๋“  ์‚ฌ๋žŒ์ด ๋‹ค๋ฅธ ๋ณต์žกํ•œ(๊ทธ๋Ÿฌ๋‚˜ ๊ฑด์ „ํ•œ) ๊ฐœ๋…์„ ๊ตฌํ˜„ํ•˜๋ ค๊ณ  ํ•  ๋•Œ๋งˆ๋‹ค ์œ ํ˜• ์‹œ์Šคํ…œ์˜ ์ด ๋ฌด์˜๋ฏธํ•œ ๊ตฌ์„์„ ์žฌ๋น ๋ฅด๊ฒŒ ์›€์ง์—ฌ์•ผ ํ•œ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์ค‘์š”ํ•˜๋‹ค๊ณ  ๋Š๋ผ๋Š” ์ด ์‚ฌ์šฉ ์‚ฌ๋ก€๊ฐ€ ํ•˜๋‚˜ ์žˆ๋‹ค๊ณ  ํ•ด์„œ(๊ธฐ์กด ์œ ํ˜• ์‹œ์Šคํ…œ์—์„œ ์›ํ•˜๋Š” ๊ฒƒ์„ ๊ฑด์ „ํ•˜๊ฒŒ ํ‘œํ˜„ํ•˜๋Š” ๋Œ€์•ˆ์  ๋ฐฉ๋ฒ•์„ ๋ณด์—ฌ์ฃผ๊ธฐ ์œ„ํ•ด ์ด ์Šค๋ ˆ๋“œ์—์„œ ์—ฌ๋Ÿฌ ๋ฒˆ ์‹œ๋„ํ–ˆ์Šต๋‹ˆ๋‹ค) ํ•ด์•ผ ํ•  ์ผ์€ ์–ด๋–ค ๋Œ€๊ฐ€๋ฅผ ์น˜๋ฅด๋”๋ผ๋„ ์ œ์•ˆ๋œ ์ ‘๊ทผ ๋ฐฉ์‹์„ ๊ณ„์† ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ ํ•จ์ˆ˜์˜ ๋ฐ˜ํ™˜ ์œ ํ˜•์„ ํฌํ•จํ•˜์—ฌ ์ž„์˜์˜ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ํด๋ž˜์Šค์— ๋ณ‘ํ•ฉํ•  ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ์‹์œผ๋กœ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ๋ฅผ ๊ณ ์ง‘ํ•œ๋‹ค๋ฉด ์•„๋ฌด๋ฐ๋„ ๊ฐ€์ง€ ๋ชปํ•˜๋Š” ๊ฒƒ์ด ๋ถˆ๊ฐ€๋Šฅํ•œ ์ผ์ด ์•„๋‹™๋‹ˆ๋‹ค.

@arackaf :

function d<T>(Class: new() => T): T & { new (): { blah(): void } } {
    return class extends Class {
        blah() { }
    };
}

extends ์ ˆ์—์„œ ์ž˜ ์ž‘๋™ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

class C extends d(S) {
  foo() {
    this.blah(); // tsc is happy here
  }
}

์œ ํ˜• ์‹œ์Šคํ…œ์—์„œ ํ›จ์”ฌ ๋” ์‰ฝ๊ณ  ์ด๋ฏธ ์ •์˜๋œ ์˜๋ฏธ ์ฒด๊ณ„๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ ์ด๋ฏธ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค. ์„ ์–ธ๋œ ํด๋ž˜์Šค์— ๋Œ€ํ•œ ์Šˆํผํด๋ž˜์Šค๋ฅผ ๋งŒ๋“œ๋Š” ๋Œ€์‹  ์„œ๋ธŒํด๋ž˜์Šค๋กœ ํ•ด๊ฒฐํ•˜๋ ค๋Š” ๋ฌธ์ œ๋Š” ๋ฌด์—‡์ž…๋‹ˆ๊นŒ?

@masaeedu

์˜ค๋Š˜๋‚  ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๊ฐ€ ์ž‘๋™ํ•˜๋Š” ๋ฐฉ์‹์€ ์ผ๋ฐ˜์ ์ธ ๊ฒฝ์šฐ์— ์ด๋ฅผ ๋ณ€๊ฒฝํ•˜๋Š” ๊ฒƒ์„ ์ •๋‹นํ™”ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

(ํด๋ž˜์Šค) ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ์˜ ์ฃผ์š” ์šฉ๋„๋Š” ์–ด๋–ค ์‹์œผ๋กœ๋“  ํด๋ž˜์Šค ๋‚ด๋ถ€์˜ this ๊ฐ’์„ ์ ˆ๋Œ€์ ์œผ๋กœ ๊ธ์ •์ ์œผ๋กœ ๋ณ€๊ฒฝํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. Redux์˜ @connect ์™€ MobX์˜ @observer ๋Š” ๋‘˜ ๋‹ค ์ˆ˜์—…์„ ๋ฐ›๊ณ  ๊ธฐ๋Šฅ์ด ์ถ”๊ฐ€๋œ ์›๋ž˜ ์ˆ˜์—…์˜ ์ƒˆ ๋ฒ„์ „์„ ๋‚ด๋ณด๋ƒ…๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ํŠน์ • ๊ฒฝ์šฐ์— this ์˜ ์‹ค์ œ ๊ตฌ์กฐ๊ฐ€ ๋ณ€๊ฒฝ๋œ๋‹ค๊ณ  ์ƒ๊ฐ ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค( this.props ์˜ ๊ตฌ์กฐ๋งŒ). ๊ทธ๋Ÿฌ๋‚˜ ๊ทธ๊ฒƒ์€ ์ค‘์š”ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์œ„์˜ ์ฃผ์„์—์„œ ๋ณผ ์ˆ˜ ์žˆ๋“ฏ์ด ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํด๋ž˜์Šค๋ฅผ ๋ณ€๊ฒฝํ•˜๋Š” ๊ฒƒ์€ ๋งค์šฐ ์ผ๋ฐ˜์ ์ธ ์‚ฌ์šฉ ์‚ฌ๋ก€์ž…๋‹ˆ๋‹ค. ๋” ์ข‹๋“  ๋‚˜์˜๋“  ์‚ฌ๋žŒ๋“ค์€ ํ†ต์‚ฌ๋ก ์  ๋Œ€์•ˆ์„ ์‹ซ์–ดํ•˜๋Š” ๊ฒฝํ–ฅ์ด ์žˆ์Šต๋‹ˆ๋‹ค.

let Foo = a(b(c(
    class Foo {
    }
})));

๋ฐ˜๋Œ€๋กœ

<strong i="19">@a</strong>
<strong i="20">@b</strong>
<strong i="21">@c</strong>
class Foo {
}

์ด์ œ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๊ฐ€

function d (Class){
    Class.prototype.blah = function(){
    };
}

๋˜๋Š”

function d(Class){
    return class extends Class {
        blah(){ }
    }
}

์ค‘์š”ํ•˜์ง€ ์•Š์•„์•ผํ•ฉ๋‹ˆ๋‹ค. ์–ด๋–ค ์‹์œผ๋กœ๋“  ๋งŽ์€ ์‚ฌ๋žŒ๋“ค์ด ์ฃผ์žฅํ•˜๋Š” ์‚ฌ์šฉ ์‚ฌ๋ก€๋Š” ์–ด๋–ค ์ฃผ์„์ด ํ•„์š”ํ•œ์ง€, ์šฐ๋ฆฌ์—๊ฒŒ ์•„๋ฌด๋ฆฌ ๋ถˆํŽธํ•˜๋”๋ผ๋„ TypeScript์— function c ๊ฐ€ C ํด๋ž˜์Šค๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค๊ณ  ์•Œ๋ฆด ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. C & {blah(): void} ๊ตฌ์กฐ์˜ ํด๋ž˜์Šค๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

์ด๊ฒƒ์ด ์˜ค๋Š˜๋‚  ์šฐ๋ฆฌ ์ค‘ ๋งŽ์€ ์‚ฌ๋žŒ๋“ค์ด ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋ฅผ ์ ๊ทน์ ์œผ๋กœ ์‚ฌ์šฉํ•˜๋Š” ์ด์œ ์ž…๋‹ˆ๋‹ค. ์šฐ๋ฆฌ๋Š” ์ด ๋™์ž‘์˜ ์œ ์šฉํ•œ ํ•˜์œ„ ์ง‘ํ•ฉ์„ ์œ ํ˜• ์‹œ์Šคํ…œ์— ํ†ตํ•ฉํ•˜๊ธฐ๋ฅผ ์ •๋ง ์›ํ•ฉ๋‹ˆ๋‹ค.

๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๊ฐ€ ์œ ํ˜• ์‹œ์Šคํ…œ์ด ์ถ”์ ํ•  ์ˆ˜ ์—†๋Š” ๊ธฐ์ดํ•œ ์ผ์„ ํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์€ ์‰ฝ๊ฒŒ ์ฆ๋ช…๋ฉ๋‹ˆ๋‹ค. ๊ดœ์ฐฎ์€! ํ•˜์ง€๋งŒ ์ฃผ์„์„ ๋‹ฌ ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์ด ์žˆ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

<strong i="38">@c</strong>
class Foo {
    hi(){ this.addedByC(); }
}

์œ ํšจํ•ฉ๋‹ˆ๋‹ค. c ์— ๋Œ€ํ•œ ์ƒˆ๋กœ์šด ์œ ํ˜• ์ฃผ์„ ๊ตฌ๋ฌธ์ด ํ•„์š”ํ•œ์ง€ ๋˜๋Š” ๊ธฐ์กด ์œ ํ˜• ์ฃผ์„ ๊ตฌ๋ฌธ์ด ์ด๋ฅผ ๋‹ฌ์„ฑํ•˜๊ธฐ ์œ„ํ•ด c ์—์„œ ์„œ๋น„์Šค๋กœ ์ œ๊ณต๋  ์ˆ˜ ์žˆ๋Š”์ง€ ๋ชจ๋ฅด๊ฒ ์ง€๋งŒ ์ผ๋ฐ˜์ ์ธ ์‚ฌ์šฉ์„ ์ˆ˜์ •ํ•˜๊ธฐ๋งŒ ํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค. ์ด ๊ฒฝ์šฐ(์›๋ž˜ ํด๋ž˜์Šค์— ์˜ํ–ฅ์„ ๋ฏธ์น˜์ง€ ์•Š๊ณ  ๊ฐ€์žฅ์ž๋ฆฌ๋ฅผ ์žˆ๋Š” ๊ทธ๋Œ€๋กœ ๋‘๋Š” ๊ฒƒ)๋Š” TS ์‚ฌ์šฉ์ž์—๊ฒŒ ํฐ ์ด์ ์ด ๋  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

@justinfagnani ์ฐธ๊ณ ํ•˜์„ธ์š”

function d<T>(Class: new() => T): T & { new (): { blah(): void } } {
    return class extends Class {
        blah() { }
    };
}

์ƒ์‚ฐํ•˜๋‹ค

'typeof(์ต๋ช… ํด๋ž˜์Šค)' ์œ ํ˜•์€ 'T & (new () => { blah(): void; })' ์œ ํ˜•์— ํ• ๋‹นํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.
'typeof(์ต๋ช… ํด๋ž˜์Šค)' ์œ ํ˜•์€ 'T' ์œ ํ˜•์— ํ• ๋‹นํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

TS ๋†€์ดํ„ฐ์—์„œ ์ผ๋ถ€ ์˜ต์…˜์ด ์ž˜๋ชป ์„ค์ •๋˜์–ด ์žˆ๋Š”์ง€ ํ™•์‹คํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์„ ์–ธ๋œ ํด๋ž˜์Šค์— ๋Œ€ํ•œ ์Šˆํผํด๋ž˜์Šค๋ฅผ ๋งŒ๋“œ๋Š” ๋Œ€์‹  ์„œ๋ธŒํด๋ž˜์Šค๋กœ ํ•ด๊ฒฐํ•˜๋ ค๋Š” ๋ฌธ์ œ๋Š” ๋ฌด์—‡์ž…๋‹ˆ๊นŒ?

๋‚˜๋Š” ๋‹จ์ง€ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋ฅผ ์‚ฌ์šฉํ•˜๋ ค๊ณ ํ•ฉ๋‹ˆ๋‹ค. 1๋…„ ๋„˜๊ฒŒ JS์—์„œ ํ–‰๋ณตํ•˜๊ฒŒ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. TS๊ฐ€ ๋”ฐ๋ผ์žก๊ธฐ๋ฅผ ๊ฐ„์ ˆํžˆ ๋ฐ”๋ผ๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ๋‚˜๋Š” ํ™•์‹คํžˆ ํ•˜์œ„ ๋ถ„๋ฅ˜์™€ ๊ฒฐํ˜ผํ•˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค. ๋•Œ๋•Œ๋กœ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋Š” ์†์„ฑ์ด๋‚˜ ๋ฉ”์„œ๋“œ๋ฅผ ์ถ”๊ฐ€ํ•˜๊ธฐ ์œ„ํ•ด ์›๋ž˜ ํด๋ž˜์Šค์˜ ํ”„๋กœํ† ํƒ€์ž…์„ ๋ณ€๊ฒฝํ•ฉ๋‹ˆ๋‹ค. ์–ด๋Š ์ชฝ์ด๋“  ๋ชฉํ‘œ๋Š” TypeScript์— ๋‹ค์Œ์„ ์•Œ๋ฆฌ๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

<strong i="17">@c</strong>
class Foo { 
}

c ์— ์˜ํ•ด ์ƒ์„ฑ๋œ ์ƒˆ ๋ฉค๋ฒ„๊ฐ€ ์žˆ๋Š” ํด๋ž˜์Šค๊ฐ€ ์ƒ์„ฑ๋ฉ๋‹ˆ๋‹ค.

@arackaf ์šฐ๋ฆฌ๋Š” ๋‹ค์‹œ ๋™๊ธฐํ™”๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ํ† ๋ก ์€ ์ด๊ฒƒ์— ๊ด€ํ•œ ๊ฒƒ์ด ์•„๋‹™๋‹ˆ๋‹ค .

<strong i="8">@a</strong>
<strong i="9">@b</strong>
<strong i="10">@c</strong>
class Foo {
}

๋Œ€ ์ด๊ฒƒ:

let Foo = a(b(c(
    class Foo {
    }
})));

๋‚˜๋Š” ๋‹น์‹ ์ด ์ „์ž๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ณ  ์—ฌ์ „ํžˆ new Foo() ์˜ ์ ์ ˆํ•œ ํƒ€์ดํ•‘์„ ๊ฐ€์งˆ ์ˆ˜ ์žˆ๊ธฐ๋ฅผ ๊ธฐ๋Œ€ํ•ฉ๋‹ˆ๋‹ค. ์ด์— ๋Œ€ํ•œ ๋…ผ์Ÿ์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

<strong i="18">@a</strong>
<strong i="19">@b</strong>
<strong i="20">@c</strong>
class Foo {
    fooMember() { 
        this.aMember(); this.bMember(); this.cMember(); 
    }
}

๋Œ€ ์ด๊ฒƒ:

class Foo extends (<strong i="24">@a</strong> <strong i="25">@b</strong> <strong i="26">@c</strong> class { }) {
    fooMember() { 
        this.aMember(); this.bMember(); this.cMember(); 
    }
}

ํ›„์ž๋Š” ์œ ํ˜• ์‹œ์Šคํ…œ์„ ์†์ƒ์‹œํ‚ค์ง€ ์•Š๊ณ  ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค. ์ „์ž๋Š” ๋‚ด๊ฐ€ ์ด๋ฏธ ์„ค๋ช…ํ•œ ์—ฌ๋Ÿฌ ๋ฉด์—์„œ ๋ฌธ์ œ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

@masaeedu ์ „์ž๊ฐ€ ์ž‘๋™ํ•˜๋„๋ก ํ•  ์ˆ˜ ์žˆ๋Š” ์ œํ•œ๋œ ์‚ฌ์šฉ ์‚ฌ๋ก€๊ฐ€ ์‹ค์ œ๋กœ ์—†์Šต๋‹ˆ๊นŒ?

์ •ํ™•ํžˆ ๋งํ•˜๋ฉด TypeScript๊ฐ€ ์œ„์˜ ์˜ˆ์—์„œ a , b ๋ฐ c ์— ์ถ”๊ฐ€ํ•˜๋„๋ก ์ง€์‹œํ•  ์ˆ˜ ์žˆ๋Š” ์ฃผ์„์ด ์—†๋Š”์ง€ ์œ ํ˜• ์‹œ์Šคํ…œ์ด ์ „์ž๋ฅผ ์ฒ˜๋ฆฌํ•˜๋„๋ก ํ•˜์‹ญ์‹œ์˜ค. ํ›„์ž์™€ ๊ตฌ๋ณ„ํ•  ์ˆ˜ ์—†์„ ์ •๋„๋กœ?

๊ทธ๊ฒƒ์€ TypeScript์˜ ํ‚ฌ๋Ÿฌ ๋ฐœ์ „์ด ๋  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

@arackaf ์ฃ„์†กํ•ฉ๋‹ˆ๋‹ค. type ๋งค๊ฐœ๋ณ€์ˆ˜๊ฐ€ ์ธ์Šคํ„ด์Šค ์œ ํ˜•์ด ์•„๋‹Œ ์ƒ์„ฑ์ž ์œ ํ˜•์„ ์ฐธ์กฐํ•˜๋„๋ก ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

์ด๊ฒƒ์€ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค:

type Constructor<T = object> = new (...args: any[]) => T;

interface Blah {
  blah(): void;
}

function d<T extends Constructor>(Class: T): T & Constructor<Blah> {
  return class extends Class {
    blah() { }
  };
}

class Foo extends d(Object) {
  protected num: number;

  constructor(num: number) {
    super();
    this.num = num;
    this.blah();
  }
}

๋‚˜๋Š” ๋‹จ์ง€ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋ฅผ ์‚ฌ์šฉํ•˜๋ ค๊ณ ํ•ฉ๋‹ˆ๋‹ค.

๊ทธ๊ฒƒ์€ ๋‹น์‹ ์ด ํ•ด๊ฒฐํ•˜๋ ค๋Š” ๋ฌธ์ œ๊ฐ€ ์•„๋‹ˆ๋ผ ๋™์–ด๋ฐ˜๋ณต์ž…๋‹ˆ๋‹ค. Q: "๊ทธ ๋ง์น˜๋กœ ๋ฌด์—‡์„ ํ•˜๋ ค๊ณ  ํ•ฉ๋‹ˆ๊นŒ?"์™€ ๊ฐ™์Šต๋‹ˆ๋‹ค. A: "๊ทธ๋ƒฅ ๋ง์น˜๋ฅผ ์‚ฌ์šฉํ•˜์„ธ์š”."

์˜๋„ํ•œ ํ™•์žฅ์œผ๋กœ ์ƒˆ ์Šˆํผํด๋ž˜์Šค๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๊ฒƒ์ด ์ž‘๋™ํ•˜์ง€ ์•Š๋Š” ์‹ค์ œ ์‚ฌ๋ก€๊ฐ€ ์žˆ์Šต๋‹ˆ๊นŒ? TypeScript๋Š” ์ง€๊ธˆ ๊ทธ๊ฒƒ์„ ์ง€์›ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๊ทธ๋ฆฌ๊ณ  ๋‚ด๊ฐ€ ๋งํ–ˆ๋“ฏ์ด, ๊ทธ ๊ฒฝ์šฐ์— ํด๋ž˜์Šค ๋‚ด๋ถ€์—์„œ ํด๋ž˜์Šค์˜ ์œ ํ˜•์— ๋Œ€ํ•ด ์ถ”๋ก ํ•˜๋Š” ๊ฒƒ์ด ํ›จ์”ฌ ์‰ฝ์Šต๋‹ˆ๋‹ค.

Mobx์˜ @observer render() ์„ ๋ณด๋‹ˆ ํด๋ž˜์Šค ๋ชจ์–‘์ด ๋ณ€๊ฒฝ๋˜์ง€ ์•Š๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ๋ณด์ž…๋‹ˆ๋‹ค.

@connect @connect ์‹ค์ œ๋กœ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋ฅผ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์ž…๋ ฅํ•˜๋Š” ๋ณต์žก์„ฑ์˜ ์ข‹์€ ์˜ˆ์ž…๋‹ˆ๋‹ค. ์ •์ ์ด ๋ณต์‚ฌ๋˜๋ฏ€๋กœ ๊ฒฐ๊ณผ๋Š” ์ธ์Šคํ„ด์Šค ์ธก ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๋ฒ„๋ฆฌ๊ณ  ๋Œ€๋ถ€๋ถ„์˜ ๊ฒฝ์šฐ TS๊ฐ€ ํ™•์ธํ•˜์ง€ ์•Š๋Š” ์ •์  ์ธก์„ ์œ ์ง€ํ•ฉ๋‹ˆ๋‹ค. @connect ๋Š” ์‹ค์ œ๋กœ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๊ฐ€ ๋˜์–ด์„œ๋Š” ์•ˆ ๋˜๋ฉฐ connect๋Š” HOC๋กœ ์‚ฌ์šฉ๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋กœ์„œ ๋งค์šฐ ํ˜ผ๋ž€์Šค๋Ÿฝ๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

1๋…„ ๋„˜๊ฒŒ JS์—์„œ ํ–‰๋ณตํ•˜๊ฒŒ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

๊ธ€์Ž„... ๋‹น์‹ ์€ ์ •๋ง. JS์—๋Š” ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. ๋‹น์‹ ์€ ์•„๋งˆ๋„ Babel๊ณผ TypeScript์—์„œ ์•ฝ๊ฐ„ ๋‹ค๋ฅด๊ฒŒ ๊ตฌํ˜„๋œ ํŠน์ • ์กด์žฌํ•˜์ง€ ์•Š๋Š” ์ด์ „ ์ œ์•ˆ์„ ์‚ฌ์šฉํ–ˆ์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋‹ค๋ฅธ ์žฅ์†Œ์—์„œ๋Š” ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๊ฐ€ ํ‘œ์ค€ํ™” ํ”„๋กœ์„ธ์Šค๋ฅผ ๊ณ„์† ์ง„ํ–‰ํ•ด์•ผ ํ•œ๋‹ค๊ณ  ์ฃผ์žฅํ•˜๊ณ  ์žˆ์ง€๋งŒ ์ง„ํ–‰ ์†๋„๊ฐ€ ๋Š๋ ค์ง€๊ณ  ์žˆ์œผ๋ฉฐ ์•„์ง ํ™•์‹คํ•˜์ง€ ์•Š๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ๋งŽ์€ ์‚ฌ๋žŒ๋“ค์€ ๊ทธ๊ฒƒ๋“ค์ด ์ถ”๊ฐ€๋˜์–ด์„œ๋Š” ์•ˆ ๋˜๊ฑฐ๋‚˜ ๋‹จ์ง€ ์ฃผ์„์ด ๋˜์–ด์„œ๋Š” ์•ˆ ๋œ๋‹ค๊ณ  ์ฃผ์žฅํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ ์˜๋ฏธ ์ฒด๊ณ„๋Š” ์—ฌ์ „ํžˆ ๊ณต์ค‘์— ๋–  ์žˆ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋ฐ์ฝ”๋ ˆ์ดํ„ฐ์— ๋Œ€ํ•œ ๋ถˆ๋งŒ ์ค‘ ํ•˜๋‚˜๋Š” ์ •ํ™•ํžˆ ํด๋ž˜์Šค์˜ ๋ชจ์–‘์„ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ์–ด ์ •์ ์œผ๋กœ ์ถ”๋ก ํ•˜๊ธฐ๊ฐ€ ์–ด๋ ต๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ผ๋ถ€ ์ œ์•ˆ์€ ์ ์–ด๋„ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๊ฐ€ ๊ทธ๋ ‡๊ฒŒ ํ•  ์ˆ˜ ์žˆ๋Š” ๋Šฅ๋ ฅ์„ ์ œํ•œํ•˜๊ธฐ ์œ„ํ•ด ๋…ผ์˜๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ๊ฐ€์žฅ ์ตœ๊ทผ์˜ ์ œ์•ˆ์— ์‚ฌ์–‘ ์–ธ์–ด๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ๋‚˜๋Š” ๊ฐœ์ธ์ ์œผ๋กœ ์„ ์˜๋กœ ํ–‰๋™ํ•˜๋Š” ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๊ฐ€ ํด๋ž˜์Šค์˜ ๋ชจ์–‘์„ ๋ณ€๊ฒฝํ•ด์„œ๋Š” ์•ˆ ๋œ๋‹ค๊ณ  ์ฃผ์žฅํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ ์ •์  ๋ถ„์„์„ ์œ„ํ•ด ๋ฌด์‹œํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํ‘œ์ค€ JS์—๋Š” ํ•จ์ˆ˜ ๊ตฌํ˜„์ด ์ˆ˜ํ–‰ํ•˜๋Š” ์ž‘์—…์„ ๋ถ„์„์— ์•Œ๋ ค์ฃผ๋Š” ์œ ํ˜• ์‹œ์Šคํ…œ์ด ์—†๋‹ค๋Š” ์ ์„ ๊ธฐ์–ตํ•˜์‹ญ์‹œ์˜ค.

  • TS๊ฐ€ ๋”ฐ๋ผ์žก์„ ์ˆ˜ ์žˆ๊ธฐ๋ฅผ ๋ฐ”๋ž„ ๋ฟ์ž…๋‹ˆ๋‹ค.

TypeScript๊ฐ€ ์–ด๋–ค ์‹์œผ๋กœ๋“  ์—ฌ๊ธฐ์—์„œ ์–ด๋–ป๊ฒŒ ๋’ค์ฒ˜์ ธ ์žˆ๋Š”์ง€ ์•Œ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ์ ์–ด๋„ ๋ฌด์—‡ ๋’ค์—? ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๊ฐ€ ์ผ์„ ํ•ฉ๋‹ˆ๋‹ค. ํด๋ž˜์Šค๊ฐ€ ์›ํ•˜๋Š” ๋ฐฉ์‹์œผ๋กœ ๋™์ž‘ํ•˜๋Š” ๋‹ค๋ฅธ ์œ ํ˜•์˜ JS๊ฐ€ ์žˆ์Šต๋‹ˆ๊นŒ?

๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋Š” ์ด์ œ 2๋‹จ๊ณ„์ด๋ฉฐ ๊ฑฐ์˜ ๋ชจ๋“  JS ํ”„๋ ˆ์ž„์›Œํฌ์—์„œ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.

@connect ์— ๊ด€ํ•ด์„œ๋Š” react-redux๊ฐ€ ๋งค๋‹ฌ ์•ฝ 250๋งŒ ๋‹ค์šด๋กœ๋“œ๋ฅผ ๊ธฐ๋กํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ๋‹น์‹ ์ด ๋‹ค๋ฅด๊ฒŒ ๊ตฌํ˜„ํ–ˆ์„ ๊ฒƒ์ด๊ธฐ ๋•Œ๋ฌธ์— ๋””์ž์ธ์ด ์–ด๋–ป๊ฒŒ๋“  "ํ‹€๋ ธ๋‹ค"๋Š” ๋ง์„ ๋“ฃ๋Š” ๊ฒƒ์€ ๋ฏฟ์„ ์ˆ˜ ์—†์„ ์ •๋„๋กœ ์˜ค๋งŒํ•ฉ๋‹ˆ๋‹ค.

ํ˜„์žฌ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๊ฐ€ ๋„์ž…ํ•œ ๋ฉ”์†Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๋ ค๋Š” ์‹œ๋„๋Š” TypeScript์—์„œ ์œ ํ˜• ์˜ค๋ฅ˜๋ฅผ ์ดˆ๋ž˜ํ•˜์—ฌ ์ธํ„ฐํŽ˜์ด์Šค ๋ณ‘ํ•ฉ, ์ถ”๊ฐ€๋œ ๋ฉ”์†Œ๋“œ์— ๋Œ€ํ•œ ์ฃผ์„ ์ˆ˜๋™ ์ถ”๊ฐ€ ๋˜๋Š” ํด๋ž˜์Šค๋ฅผ ๋ณ€๊ฒฝํ•˜๊ธฐ ์œ„ํ•ด ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” ๊ฒƒ๊ณผ ๊ฐ™์€ ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ๋งˆ์‹ญ์‹œ์˜ค).

๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๊ฐ€ ํด๋ž˜์Šค ๋ชจ์–‘์„ ๋ณ€๊ฒฝํ•˜๊ณ  ์žˆ๋‹ค๋Š” ์‚ฌ์‹ค์„ TS ์ปดํŒŒ์ผ๋Ÿฌ์— ์ˆ˜๋™์œผ๋กœ ๊ณต๋“ค์—ฌ ์•Œ๋ฆฌ๋Š” ๋ฐฉ๋ฒ•์ด ์ •๋ง๋กœ ์—†์„๊นŒ์š”? ์–ด์ฉŒ๋ฉด ์ด๊ฒƒ์€ ๋ฏธ์ณค์ง€๋งŒ TS๋Š” ์ƒˆ๋กœ์šด ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋ฅผ ๋ฐฐ์†กํ•  ์ˆ˜ ์—†์—ˆ์Šต๋‹ˆ๋‹ค.์šฐ๋ฆฌ๊ฐ€ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ์œ ํ˜•

let c : ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ

๊ทธ๋ฆฌ๊ณ  ํ•ด๋‹น ์œ ํ˜•์˜ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๊ฐ€ ํด๋ž˜์Šค์— ์ ์šฉ๋˜๋Š” ๊ฒฝ์šฐ์—๋งŒ IF, TS๋Š” ํ•ด๋‹น ํด๋ž˜์Šค๋ฅผ Input & { blah() } ?

๋ง ๊ทธ๋Œ€๋กœ ๋ชจ๋“  ์‚ฌ๋žŒ๋“ค์€ ์šฐ๋ฆฌ๊ฐ€ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๋‹ค๋Š” ๊ฒƒ์„ ์•Œ๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ๋˜ํ•œ ๋ณด์ปฌ ๊ทธ๋ฃน์ด ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋ฅผ ์‹ซ์–ดํ•œ๋‹ค๋Š” ๊ฒƒ๋„ ์•Œ๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ๊ฒŒ์‹œ๋ฌผ์€ ์–ด๋–ป๊ฒŒ TS๊ฐ€ ์–ด๋–ป๊ฒŒ๋“  ํ˜•์‹ ์‹œ์Šคํ…œ์ด ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๊ฐ€ ํด๋ž˜์Šค ์ •์˜๋ฅผ ๋ณ€๊ฒฝํ•˜๊ณ  ์žˆ์Œ์„ ์ดํ•ดํ•˜๋„๋ก ํ•  ์ˆ˜ ์žˆ๋Š”์ง€์— ๊ด€ํ•œ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๊ทธ๊ฒƒ์€ ๋งŽ์€ ์‚ฌ๋žŒ๋“ค์—๊ฒŒ ํฐ ๋„์›€์ด ๋  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์ •ํ™•ํžˆ ๋งํ•˜๋ฉด TypeScript๊ฐ€ ์œ„์˜ ์˜ˆ์—์„œ ์œ ํ˜• ์‹œ์Šคํ…œ์ด ์ „์ž๋ฅผ ํ›„์ž์™€ ๊ตฌ๋ณ„ํ•  ์ˆ˜ ์—†๋„๋ก ์ฒ˜๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด ์œ„์˜ ์˜ˆ์—์„œ, b, c์— ์ถ”๊ฐ€ํ•˜๋„๋ก ์ง€์‹œํ•  ์ˆ˜ ์žˆ๋Š” ์ฃผ์„์ด ์—†์Šต๋‹ˆ๊นŒ?

์˜ˆ, ์›ํ•˜๋Š” Foo ์˜ ๋ชจ์–‘์„ ์„ ์–ธํ•˜๋Š” ๊ฒƒ์€ ๋งค์šฐ ์‰ฝ์Šต๋‹ˆ๋‹ค. ์ธํ„ฐํŽ˜์ด์Šค ๋ณ‘ํ•ฉ์„ ์‚ฌ์šฉํ•˜๊ธฐ๋งŒ ํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค. ๋‹ค์Œ์„ ์ˆ˜ํ–‰ํ•˜๊ธฐ๋งŒ ํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.

interface Foo extends <whateverextramembersiwantinfoo> { } 
<strong i="9">@a</strong>
<strong i="10">@b</strong>
<strong i="11">@c</strong>
class Foo { 
    /* have fun */
}

์ง€๊ธˆ ๋‹น์žฅ์€ ๋ฐ˜ํ™˜๋˜๋Š” ํ•ญ๋ชฉ์— ํ•ด๋‹นํ•˜๋Š” ๋งค๊ฐœ๋ณ€์ˆ˜ํ™”๋œ ํ˜•์‹์„ ๋‚ด๋ณด๋‚ด๋Š” ๋ฐ ์‚ฌ์šฉํ•˜๋Š” ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๊ฐ€ ๋ฌด์—‡์ด๋“  ์˜ˆ์ƒํ•ด์•ผ ํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด ์ถ”๊ฐ€ํ•˜๋ ค๋Š” ๋ฉค๋ฒ„๋ฅผ ์ง์ ‘ ์„ ์–ธํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. #6606 ์„ ์–ป์œผ๋ฉด interface Foo extends typeof(a(b(c(Foo)))) ํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.

ํ˜„์žฌ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๊ฐ€ ๋„์ž…ํ•œ ๋ฉ”์†Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๋ ค๋Š” ์‹œ๋„๋Š” TypeScript์—์„œ ์œ ํ˜• ์˜ค๋ฅ˜๋ฅผ ์ดˆ๋ž˜ํ•˜์—ฌ ์ธํ„ฐํŽ˜์ด์Šค ๋ณ‘ํ•ฉ, ์ถ”๊ฐ€๋œ ๋ฉ”์†Œ๋“œ์— ๋Œ€ํ•œ ์ฃผ์„ ์ˆ˜๋™ ์ถ”๊ฐ€ ๋˜๋Š” ํด๋ž˜์Šค๋ฅผ ๋ณ€๊ฒฝํ•˜๊ธฐ ์œ„ํ•ด ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” ๊ฒƒ๊ณผ ๊ฐ™์€ ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ๋งˆ์‹ญ์‹œ์˜ค).

๋ฐ์ฝ”๋ ˆ์ดํ„ฐ ๋„์ž… ๋ฉค๋ฒ„์— ๋ถˆ๊ฐ€์ง€๋ก ์ ์ผ ๋•Œ ์ž‘์„ฑ ์ค‘์ธ ํด๋ž˜์Šค๋ฅผ ๋ฐ์ฝ”๋ ˆ์ดํŒ…ํ•˜๊ณ  ๊ทธ๋ ‡์ง€ ์•Š์€ ๊ฒฝ์šฐ ๋ฐ์ฝ”๋ ˆ์ดํŒ…๋œ ํด๋ž˜์Šค๋ฅผ ํ™•์žฅํ•˜๋Š” ์˜ต์…˜์„ ์–ธ๊ธ‰ํ•˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค. ์ด๊ฒƒ์ด ๋‚ด๊ฐ€ ์ตœ์†Œํ•œ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์ž…๋‹ˆ๋‹ค.

์ง€๊ธˆ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์˜ ์ฝ”๋“œ ์Šค๋‹ˆํŽซ์„ ์•Œ๋ ค์ฃผ์‹ค ์ˆ˜ ์žˆ๋‚˜์š”? ์ด๊ฒƒ์ด ๋ฌธ์ œ๊ฐ€ ๋˜๋Š” ๋ถ€๋ถ„์ž…๋‹ˆ๋‹ค.

์ฃ„์†กํ•ฉ๋‹ˆ๋‹ค. ๊ท€ํ•˜์˜ ๋งˆ์ง€๋ง‰ ์˜๊ฒฌ์„ ๋”ฐ๋ฅด์ง€ ์•Š์•˜์ง€๋งŒ ์ธํ„ฐํŽ˜์ด์Šค ๋ณ‘ํ•ฉ๊ณผ ํ•จ๊ป˜ ๊ทธ ์ด์ „์˜ ๊ท€ํ•˜์˜ ์˜๊ฒฌ์€ ์ •ํ™•ํžˆ ์ œ๊ฐ€ ์ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๋Š” ๋ฐฉ๋ฒ•์ž…๋‹ˆ๋‹ค.

ํ˜„์žฌ ๋‚ด ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋Š” Type๋„ ๋‚ด๋ณด๋‚ด์•ผ ํ•˜๋ฉฐ, ๋ณด์—ฌ์ฃผ์‹  ๋Œ€๋กœ ์ธํ„ฐํŽ˜์ด์Šค ๋ณ‘ํ•ฉ์„ ์‚ฌ์šฉํ•˜์—ฌ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ์— ์˜ํ•ด ์ƒˆ ๊ตฌ์„ฑ์›์ด ์ถ”๊ฐ€๋˜๊ณ  ์žˆ์Œ์„ TS์— ๋‚˜ํƒ€๋ƒ…๋‹ˆ๋‹ค. ๋งŽ์€ ์‚ฌ๋žŒ๋“ค์ด ์—ด๋งํ•˜๋Š” ์ด ์ถ”๊ฐ€๋œ ์ƒ์šฉ๊ตฌ๋ฅผ ๋ฒ„๋ฆฌ๋Š” ๊ธฐ๋Šฅ์ž…๋‹ˆ๋‹ค.

@arackaf ์•„๋งˆ๋„ ๋‹น์‹ ์ด ์ •๋ง๋กœ ์›ํ•˜๋Š” ๊ฒƒ์€ ํ•จ์ˆ˜ ์ธ์ˆ˜์˜ ์ปจํ…์ŠคํŠธ ํƒ€์ดํ•‘๊ณผ ์ƒํ˜ธ์ž‘์šฉํ•˜๊ธฐ ์œ„ํ•ด ์„ ์–ธ ๋ณ‘ํ•ฉ์„ ์œ„ํ•œ ๋ฐฉ๋ฒ•์ผ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

ํ™•์‹ ํ•˜๋Š”. ๋‚˜๋Š” ํด๋ž˜์Šค์—์„œ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ธฐ๋Šฅ์„ ์›ํ•˜๊ณ  ๊ฐœ๋…์ ์œผ๋กœ ๋‚ด๊ฐ€ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋ฅผ ์ •์˜ํ•œ ๋ฐฉ๋ฒ•์— ๋”ฐ๋ผ ์ผ๋ถ€ ์ธํ„ฐํŽ˜์ด์Šค ๋ณ‘ํ•ฉ์ด ๋ฐœ์ƒํ•˜์—ฌ ๋ฐ์ฝ”๋ ˆ์ดํŒ…๋œ ํด๋ž˜์Šค์— ์ถ”๊ฐ€ ๋ฉค๋ฒ„๊ฐ€ ์ถ”๊ฐ€๋˜๊ธฐ๋ฅผ ์›ํ•ฉ๋‹ˆ๋‹ค.

๋‚˜๋Š” ๊ทธ๊ฒƒ์ด ์ผ์–ด๋‚˜๋„๋ก ๋‚ด ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ์— ์–ด๋–ป๊ฒŒ ์ฃผ์„์„ ๋‹ฌ์•„์•ผ ํ•˜๋Š”์ง€ ์ „ํ˜€ ๋ชจ๋ฅด์ง€๋งŒ, ๋‚˜๋Š” ๊ทธ๋‹ค์ง€ ๊นŒ๋‹ค๋กญ์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋ฏธ๋ž˜์˜ TS ๋ฒ„์ „์ด ์ €์—๊ฒŒ ์˜ํ–ฅ์„ ์ค€ ์–ด๋–ค ๊ตฌ๋ฌธ๋„ ์ €๋ฅผ ์—„์ฒญ๋‚˜๊ฒŒ ํ–‰๋ณตํ•˜๊ฒŒ ๋งŒ๋“ค ๊ฒƒ์ž…๋‹ˆ๋‹ค. :)

๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋Š” ์ด์ œ 2๋‹จ๊ณ„์ด๋ฉฐ ๊ฑฐ์˜ ๋ชจ๋“  JS ํ”„๋ ˆ์ž„์›Œํฌ์—์„œ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.

๊ทธ๋ฆฌ๊ณ  ๊ทธ๋“ค์€ ๋‹จ์ง€ 2๋‹จ๊ณ„์— ์žˆ๊ณ  ๋งค์šฐ ๋Š๋ฆฌ๊ฒŒ ์›€์ง์ด๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ๋‚˜๋Š” ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๊ฐ€ ์ผ์–ด๋‚˜๊ธฐ๋ฅผ ๊ฐ„์ ˆํžˆ ๋ฐ”๋ผ๊ณ  ๊ทธ๋“ค์ด ํ•จ๊ป˜ ์›€์ง์ด๋„๋ก ๋„์šธ ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์„ ์•Œ์•„ ๋‚ด๋ ค๊ณ  ๋…ธ๋ ฅํ•˜๊ณ  ์žˆ์ง€๋งŒ ๊ทธ๋“ค์€ ์—ฌ์ „ํžˆ โ€‹โ€‹ํ™•์‹คํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋‚˜๋Š” ์—ฌ์ „ํžˆ ํ”„๋กœ์„ธ์Šค์— ์˜ํ–ฅ์„ ๋ฏธ์น  ์ˆ˜ ์žˆ๋Š” ์‚ฌ๋žŒ๋“ค์ด ๊ทธ๋“ค์—๊ฒŒ ๋ฐ˜๋Œ€ํ•˜๊ฑฐ๋‚˜ ์ฃผ์„์œผ๋กœ ์ œํ•œ๋˜๊ธฐ๋ฅผ ์›ํ•˜๋Š” ์‚ฌ๋žŒ๋“ค์„ ์•Œ๊ณ  ์žˆ์ง€๋งŒ ๊ทธ๋“ค์ด ๋ฐฉํ•ดํ•  ๊ฒƒ์ด๋ผ๊ณ ๋Š” _์ƒ๊ฐํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค_. JS๊ฐ€ ์•„๋‹Œ ํ˜„์žฌ ์ปดํŒŒ์ผ๋Ÿฌ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ ๊ตฌํ˜„์— ๋Œ€ํ•œ ๋‚ด ์š”์ ์€ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค.

@connect ์˜ ๊ฒฝ์šฐ react-redux๋Š” ํ•œ ๋‹ฌ์— ์•ฝ 250๋งŒ ๋‹ค์šด๋กœ๋“œ๋ฅผ ๊ธฐ๋กํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ๋‹น์‹ ์ด ๋‹ค๋ฅด๊ฒŒ ๊ตฌํ˜„ํ–ˆ์„ ๊ฒƒ์ด๊ธฐ ๋•Œ๋ฌธ์— ๋””์ž์ธ์ด ์–ด๋–ป๊ฒŒ๋“  "ํ‹€๋ ธ๋‹ค"๋Š” ๋ง์„ ๋“ฃ๋Š” ๊ฒƒ์€ ๋ฏฟ์„ ์ˆ˜ ์—†์„ ์ •๋„๋กœ ์˜ค๋งŒํ•ฉ๋‹ˆ๋‹ค.

์ €๋ฅผ ์˜ค๋งŒํ•˜๊ฒŒ ํ•˜๋Š” ๋“ฑ ์ธ์‹ ๊ณต๊ฒฉ์€ ์‚ผ๊ฐ€ํ•ด ์ฃผ์‹ญ์‹œ์˜ค.

  1. ๋‚ด๊ฐ€ ์ธ์‹ ๊ณต๊ฒฉํ•œ๊ฒŒ ์•„๋‹ˆ๋‹ˆ๊นŒ ์ธ์‹ ๊ณต๊ฒฉํ•˜์ง€๋งˆ.
  2. ๋‹น์‹ ์˜ ์ฃผ์žฅ์— ์ „ํ˜€ ๋„์›€์ด ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
  3. ํ”„๋กœ์ ํŠธ์˜ ์ธ๊ธฐ๊ฐ€ ๊ธฐ์ˆ  ๋น„ํ‰์—์„œ ์ œ์™ธ๋˜์–ด์„œ๋Š” ์•ˆ ๋ฉ๋‹ˆ๋‹ค.
  4. ์šฐ๋ฆฌ๋Š” ๊ฐ™์€ ๊ฒƒ์— ๋Œ€ํ•ด ์ด์•ผ๊ธฐํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๊นŒ? redux-connect-decorator๋Š” ํ•˜๋ฃจ์— 4๋ฒˆ ๋‹ค์šด๋กœ๋“œ๋ฉ๋‹ˆ๋‹ค. react-redux์˜ connect() ํ•จ์ˆ˜๋Š” ๋‚ด๊ฐ€ ์ œ์•ˆํ•œ ๊ฒƒ์ฒ˜๋Ÿผ HOC์ฒ˜๋Ÿผ ๋ณด์ž…๋‹ˆ๋‹ค.
  5. ๋‚ด ์ƒ๊ฐ์— ์„ ํ•œ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋Š” ํด๋ž˜์Šค์˜ ๊ณต๊ฐœ ํ˜•ํƒœ๋ฅผ ๋ณ€๊ฒฝํ•ด์„œ๋Š” ์•ˆ ๋˜๋ฉฐ ํ™•์‹คํžˆ ๊ด€๋ จ ์—†๋Š” ํด๋ž˜์Šค๋กœ ๋Œ€์ฒดํ•ด์•ผ ํ•˜๋ฉฐ ๊ฝค ํ•ฉ๋ฆฌ์ ์ด๋ฉฐ JS ์ปค๋ฎค๋‹ˆํ‹ฐ์—์„œ ์ถฉ๋ถ„ํ•œ ๋™์˜๋ฅผ ์–ป์„ ๊ฒƒ์ด๋ผ๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ๋™์˜ํ•˜์ง€ ์•Š๋”๋ผ๋„ ์˜ค๋งŒํ•จ๊ณผ๋Š” ๊ฑฐ๋ฆฌ๊ฐ€ ๋ฉ€๋‹ค.

ํ˜„์žฌ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๊ฐ€ ๋„์ž…ํ•œ ๋ฉ”์†Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๋ ค๋Š” ์‹œ๋„๋Š” TypeScript์—์„œ ์œ ํ˜• ์˜ค๋ฅ˜๋ฅผ ์ดˆ๋ž˜ํ•˜์—ฌ ์ธํ„ฐํŽ˜์ด์Šค ๋ณ‘ํ•ฉ, ์ถ”๊ฐ€๋œ ๋ฉ”์†Œ๋“œ์— ๋Œ€ํ•œ ์ฃผ์„ ์ˆ˜๋™ ์ถ”๊ฐ€ ๋˜๋Š” ํด๋ž˜์Šค๋ฅผ ๋ณ€๊ฒฝํ•˜๊ธฐ ์œ„ํ•ด ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” ๊ฒƒ๊ณผ ๊ฐ™์€ ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ๋งˆ์‹ญ์‹œ์˜ค).

์šฐ๋ฆฌ๊ฐ€ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋ฅผ ์ „ํ˜€ ์‚ฌ์šฉํ•˜์ง€ ๋ง๋ผ๊ณ  ์ œ์•ˆํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ, @masaeedu ๊ฐ€ ํ˜•์‹ ์•ˆ์ „ ๋ฐฉ์‹์œผ๋กœ ํ”„๋กœํ† ํƒ€์ž…์„ ์ˆ˜์ •ํ•˜๊ธฐ ์œ„ํ•ด ๊ธฐ์กด ๋ฉ”์ปค๋‹ˆ์ฆ˜์ธ ์ƒ์† ๋ฐ ๋ฏน์Šค์ธ ์‘์šฉ ํ”„๋กœ๊ทธ๋žจ์ด ์žˆ๋‹ค๊ณ  ๋งํ•ฉ๋‹ˆ๋‹ค. d ์˜ˆ์ œ๊ฐ€ ๋ฏน์Šค์ธ์œผ๋กœ ์‚ฌ์šฉํ•˜๊ธฐ์— ์ ํ•ฉํ•˜์ง€ ์•Š์€ ์ด์œ ๋ฅผ ๋ฌผ์–ด๋ณด๋ ค๊ณ  ํ–ˆ๋Š”๋ฐ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์‹ถ๋‹ค๋Š” ๋ง ์™ธ์—๋Š” ๋‹ต๋ณ€์„ ํ•˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค.

๋‚ด ์ƒ๊ฐ์—๋Š” ๊ดœ์ฐฎ์ง€๋งŒ ๋Œ€ํ™”๋ฅผ ์ƒ๋‹นํžˆ ๋น„ํŒ์ ์œผ๋กœ ์ œํ•œํ•˜๋Š” ๊ฒƒ ๊ฐ™์œผ๋ฏ€๋กœ ๋‹ค์‹œ ๊ณ ๊ฐœ๋ฅผ ์ˆ™์ด๊ฒ ์Šต๋‹ˆ๋‹ค.

@justinfagnani ๋‚ด๊ฐ€ ๋งํ•˜๋˜

import {connect} from 'react-redux'

connect ์œ„์—์„œ ๋งํ–ˆ๋“ฏ์ด ํด๋ž˜์Šค(์ปดํฌ๋„ŒํŠธ)๋ฅผ ๋ฐ›์•„์„œ ๋‹ค๋ฅธ ๊ฒƒ์„ ๋ฑ‰์–ด๋‚ด๋Š” ํ•จ์ˆ˜๊ฐ€ ์žˆ์„ ๋ฟ์ž…๋‹ˆ๋‹ค.

ํ˜„์žฌ Babel๊ณผ TypeScript์—์„œ ๋‹ค์Œ๊ณผ ๊ฐ™์ด connect ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์˜ต์…˜์ด ์žˆ์Šต๋‹ˆ๋‹ค.

class UnConnectedComponent extends Component {
}

let Component = connect(state => state.foo)(UnConnectedComponent);

๋˜๋Š” ์ด์™€ ๊ฐ™์ด

@connect(state => state.foo)
class Component extends Component {
}

๋‚˜๋Š” ์šฐ์—ฐํžˆ ํ›„์ž๋ฅผ ์„ ํ˜ธํ•˜์ง€๋งŒ ๋‹น์‹ ์ด๋‚˜ ๋‹ค๋ฅธ ๋ˆ„๊ตฐ๊ฐ€๊ฐ€ ์ „์ž๋ฅผ ์„ ํ˜ธํ•œ๋‹ค๋ฉด ๊ทธ๋ ‡๊ฒŒ ํ•˜์‹ญ์‹œ์˜ค. ๋งŽ์€ ๋„๋กœ๊ฐ€ ๋กœ๋งˆ๋กœ ์—ฐ๊ฒฐ๋ฉ๋‹ˆ๋‹ค. ๋‚˜๋Š” ๋น„์Šทํ•˜๊ฒŒ ์„ ํ˜ธํ•œ๋‹ค

<strong i="19">@mappable</strong>
<strong i="20">@vallidated</strong>
class Foo {
}

~ ์œ„์—

let Foo = validated(mappable(class Foo {
}));

๋˜๋Š”

class Foo extends mixin(validated(mappable)) {
}
//or however that would look.

๋‚ด๊ฐ€ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์ด์œ ๊ฐ€ ๋ถ„๋ช…ํ•˜๋‹ค๊ณ  ์ƒ๊ฐํ–ˆ๊ธฐ ๋•Œ๋ฌธ์— ๊ท€ํ•˜์˜ ์งˆ๋ฌธ์— ๋ช…์‹œ์ ์œผ๋กœ ๋Œ€๋‹ตํ•˜์ง€ ์•Š์•˜์ง€๋งŒ ๋ช…์‹œ์ ์œผ๋กœ ๋งํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ €๋Š” ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๊ฐ€ ์ œ๊ณตํ•˜๋Š” ์ธ์ฒด ๊ณตํ•™ ๋ฐ ๊ตฌ๋ฌธ์„ ์„ ํ˜ธํ•ฉ๋‹ˆ๋‹ค. ์ด ์ „์ฒด ์Šค๋ ˆ๋“œ๋Š” ์ธํ„ฐํŽ˜์ด์Šค ๋ณ‘ํ•ฉ๊ณผ ๊ฐ™์€ ์ƒ์šฉ๊ตฌ๋ฅผ ํ•„์š”๋กœ ํ•˜์ง€ ์•Š๋„๋ก ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๊ฐ€ ๋ฌธ์ œ์˜ ํด๋ž˜์Šค๋ฅผ ์–ด๋–ป๊ฒŒ ๋ณ€๊ฒฝํ•˜๋Š”์ง€ TS์— ์•Œ๋ ค์ฃผ๋Š” ๊ธฐ๋Šฅ์„ ์–ป์œผ๋ ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

OP๊ฐ€ ์˜ˆ์ „์— ๋งํ–ˆ๋“ฏ์ด ์šฐ๋ฆฌ๋Š” ๋‹จ์ง€ ์›ํ•ฉ๋‹ˆ๋‹ค.

declare function Blah<T>(target: T): T & {foo: number}

<strong i="31">@Blah</strong>
class Foo {
    bar() {
        return this.foo; // Property 'foo' does not exist on type 'Foo'
    }
}

new Foo().foo; // Property 'foo' does not exist on type 'Foo'

๊ทธ๋ƒฅ ์ผํ•˜๊ธฐ ์œ„ํ•ด. ์ด ํŠน์ • ๊ตฌ๋ฌธ์— ๋Œ€ํ•œ ๋‹ค๋ฅธ ๋Œ€์•ˆ์ด ์กด์žฌํ•œ๋‹ค๋Š” ์‚ฌ์‹ค์€ ๋ช…๋ฐฑํ•˜๊ณ  ์ค‘์š”ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. JS/TS ์ปค๋ฎค๋‹ˆํ‹ฐ์˜ ๋งŽ์€ ์‚ฌ๋žŒ๋“ค์ด ์ด ํŠน์ • ๊ตฌ๋ฌธ์„ ์‹ซ์–ดํ•œ๋‹ค๋Š” ์‚ฌ์‹ค ๋˜ํ•œ ๋ช…๋ฐฑํ•˜๊ณ  ์ค‘์š”ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

TS๊ฐ€ ์ด ๊ตฌ๋ฌธ์ด ์ž‘๋™ํ•˜๋„๋ก ํ•˜๋Š” ๋ฐฉ๋ฒ•์ด ์ œํ•œ์ ์ด๊ธด ํ•˜์ง€๋งŒ ์ œ๊ณตํ•  ์ˆ˜ ์žˆ๋‹ค๋ฉด ์–ธ์–ด์™€ ์ปค๋ฎค๋‹ˆํ‹ฐ์— ํฐ ์ด์ ์ด ๋  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

@arackaf connect ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด $# this ์˜ ์ถ”๊ฐ€ ๊ตฌ์„ฑ์›์— ์•ก์„ธ์Šคํ•ด์•ผ ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์–ธ๊ธ‰ํ•˜๋Š” ๊ฒƒ์„ ์†Œํ™€ํžˆ ํ–ˆ์Šต๋‹ˆ๋‹ค. AFAICT, ๊ตฌ์„ฑ ์š”์†Œ ๊ตฌํ˜„์€ connect ๊ฐ€ ์ˆ˜ํ–‰ํ•˜๋Š” ์ž‘์—…์— ์™„์ „ํžˆ ๋ถˆ๊ฐ€์ง€๋ก ์ ์ด์–ด์•ผ ํ•˜๋ฉฐ ์ž์ฒด props ๋ฐ state ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฐ ์˜๋ฏธ์—์„œ connect ๊ฐ€ ๋””์ž์ธ๋œ ๋ฐฉ์‹์€ ๋‹น์‹ ๋ณด๋‹ค @justinfagnani ์˜ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ ์‚ฌ์šฉ๋ฒ•๊ณผ ๋” ์ผ์น˜ํ•ฉ๋‹ˆ๋‹ค.

์„ค๋งˆ. ๊ณ ๋ คํ•˜๋‹ค

@connect(state => state.stuffThatSatisfiesPropsShape)
class Foo extends Component<PropsShape, any> {
}

๊ทธ๋Ÿผ ๋‚˜์ค‘์—

<Foo />

๊ทธ๊ฒƒ์€ ์œ ํšจํ•ด์•ผํ•ฉ๋‹ˆ๋‹ค - PropsShape ์†Œํ’ˆ์€ Redux ์ €์žฅ์†Œ์—์„œ ์ œ๊ณต๋˜์ง€๋งŒ TypeScript๋Š” Foo์˜ ์›๋ž˜ ์ •์˜์—์„œ ๋ฒ—์–ด๋‚˜๊ธฐ ๋•Œ๋ฌธ์— ์ด๊ฒƒ์„ ์•Œ์ง€ ๋ชปํ•ฉ๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ๋ˆ„๋ฝ๋œ ์†Œํ’ˆ์— ๋Œ€ํ•œ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•˜๊ณ  any ๋กœ ์บ์ŠคํŒ…ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

ํ•˜์ง€๋งŒ ๋ถ„๋ช…ํžˆ ํ•˜์ž๋ฉด, ์›๋ž˜ OP์—์„œ ์ œ๊ณตํ•œ ์ •ํ™•ํ•œ ์‚ฌ์šฉ ์‚ฌ๋ก€๋Š” ์—ฌ๊ธฐ ์œ„์˜ ๋‘ ๋ฒˆ์งธ ์„ค๋ช…์—์„œ ๋ณต์ œ๋œ ๊ฒƒ์œผ๋กœ, ์šฐ๋ฆฌ ์ฝ”๋“œ ๊ธฐ๋ฐ˜๊ณผ ๊ทธ ์™ธ์–‘์—์„œ ๋ณผ ๋•Œ ๋‹ค๋ฅธ ๋งŽ์€ ์‚ฌ๋žŒ๋“ค์—๊ฒŒ๋„ ๋งค์šฐ ์ผ๋ฐ˜์ ์ž…๋‹ˆ๋‹ค. ์šฐ๋ฆฌ๋Š” ๋ง ๊ทธ๋Œ€๋กœ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๊ฒƒ์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

<strong i="6">@validated</strong>
<strong i="7">@mappable</strong>
class Foo {
}

๊ทธ๋ฆฌ๊ณ  TypeScript๋ฅผ ๋งŒ์กฑ์‹œํ‚ค๊ธฐ ์œ„ํ•ด ์ผ๋ถ€ ์ธํ„ฐํŽ˜์ด์Šค ๋ณ‘ํ•ฉ์„ ์ถ”๊ฐ€ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ํ•ด๋‹น ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ ์ •์˜์— ํˆฌ๋ช…ํ•˜๊ฒŒ ๋ณ‘ํ•ฉํ•˜๋Š” ๋ฐฉ๋ฒ•์ด ์žˆ์œผ๋ฉด ์ •๋ง ์ข‹์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์šฐ๋ฆฌ๋Š” ์ด๊ฒƒ์œผ๋กœ ๊ณ„์†ํ•ด์„œ ์›์„ ๊ทธ๋ฆฌ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. Foo ์˜ ์œ ํ˜•์ด connect ์˜ ๋ฐ˜ํ™˜ ์œ ํ˜•์ด์–ด์•ผ ํ•œ๋‹ค๋Š” ๋ฐ ๋™์˜ ํ•ฉ๋‹ˆ๋‹ค. ์šฐ๋ฆฌ๋Š” ์ด์— ๋Œ€ํ•ด ์ „์ ์œผ๋กœ ๋™์˜ํ•ฉ๋‹ˆ๋‹ค.

์šฐ๋ฆฌ๊ฐ€ ๋‹ค๋ฅธ ์ ์€ Foo ๋‚ด๋ถ€ ์˜ ๋ฉค๋ฒ„๊ฐ€ this ๊ฐ€ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ ๋ฐ˜ํ™˜ ์œ ํ˜•๊ณผ ๊ทธ๊ฒƒ์ด ์˜๋ฏธํ•˜๋Š” "์›๋ž˜ Foo"์˜ ์ผ์ข…์˜ ์žฌ๊ท€์  ์œตํ•ฉ์ธ ๊ฒƒ์ฒ˜๋Ÿผ ๊ฐ€์žฅํ•ด์•ผ ํ•˜๋Š”์ง€ ์—ฌ๋ถ€์ž…๋‹ˆ๋‹ค. ์ด์— ๋Œ€ํ•œ ์‚ฌ์šฉ ์‚ฌ๋ก€๋ฅผ ์‹œ์—ฐ ํ•˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค .

์šฐ๋ฆฌ๊ฐ€ ๋‹ค๋ฅธ ์ ์€ Foo ๋‚ด๋ถ€์˜ ๊ตฌ์„ฑ์›์ด ์ด๊ฒƒ์ด ์˜๋ฏธํ•˜๋Š” ๊ฒƒ์ด ๋ฌด์—‡์ด๋“  ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ ๋ฐ˜ํ™˜ ์œ ํ˜•๊ณผ "์›๋ž˜ Foo"์˜ ์ผ์ข…์˜ ์žฌ๊ท€์  ์œตํ•ฉ์ธ ์ฒ™ํ•ด์•ผ ํ•˜๋Š”์ง€ ์—ฌ๋ถ€์ž…๋‹ˆ๋‹ค. ์ด์— ๋Œ€ํ•œ ์‚ฌ์šฉ ์‚ฌ๋ก€๋ฅผ ์‹œ์—ฐํ•˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค.

๋‚˜๋Š” ๊ฐ€์ง€๊ณ ์žˆ๋‹ค. ์œ„์˜ ๋‚ด ์˜๊ฒฌ๊ณผ ๊ทธ ๋ฌธ์ œ์— ๋Œ€ํ•ด์„œ๋Š” OP์˜ ์›๋ž˜ ์ฝ”๋“œ๋ฅผ ์ฐธ์กฐํ•˜์‹ญ์‹œ์˜ค. ์ด๊ฒƒ์€ ๋งค์šฐ ์ผ๋ฐ˜์ ์ธ ์‚ฌ์šฉ ์‚ฌ๋ก€์ž…๋‹ˆ๋‹ค.

connect ์ด ๊ตฌ์„ฑ ์š”์†Œ ๋‚ด๋ถ€์—์„œ ์•ก์„ธ์Šคํ•  ๊ฒƒ์œผ๋กœ ์˜ˆ์ƒ๋˜๋Š” ํ”„๋กœํ† ํƒ€์ž…์— ์ถ”๊ฐ€๋˜๋Š” ํ•ญ๋ชฉ์„ ๋ณด์—ฌ์ฃผ์„ธ์š”. ๋Œ€๋‹ต์ด "์•„๋ฌด๊ฒƒ๋„"์ด๋ฉด ์™„์ „ํžˆ ๊ด€๋ จ์ด ์—†์œผ๋ฏ€๋กœ connect ๋ฅผ ๋‹ค์‹œ ์–ธ๊ธ‰ํ•˜์ง€ ๋งˆ์‹ญ์‹œ์˜ค.

@masaeedu ์ถฉ๋ถ„ํžˆ ๊ณต์ •ํ•˜๊ณ  ๋™์˜ํ•ฉ๋‹ˆ๋‹ค. ๋‚˜๋Š” ์ฃผ๋กœ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๊ฐ€ ์›๋ž˜ ํด๋ž˜์Šค๋ฅผ ์ˆ˜์ •ํ•˜์ง€ ์•Š์•„์•ผ ํ•˜๋Š” ๋ฐฉ๋ฒ•, connect ์ด ์ž˜๋ชป ์„ค๊ณ„๋˜์—ˆ๋Š”์ง€ ๋“ฑ์— ๋Œ€ํ•œ @justinfagnani ์˜ ์ฃผ์žฅ์— ์‘๋‹ตํ–ˆ์Šต๋‹ˆ๋‹ค.

๋‚˜๋Š” ๋‹จ์ง€ ๋‹ค๋ฅธ ์˜ต์…˜์ด ์กด์žฌํ•œ๋‹ค๋Š” ์‚ฌ์‹ค์—๋„ ๋ถˆ๊ตฌํ•˜๊ณ  I ๋ฐ ๋งŽ์€ ๋‹ค๋ฅธ ์‚ฌ๋žŒ๋“ค์ด ์„ ํ˜ธํ•˜๋Š” ๊ตฌ๋ฌธ์„ ์‹œ์—ฐํ–ˆ์„ ๋ฟ์ž…๋‹ˆ๋‹ค.

์ด ๊ฒฝ์šฐ, ์˜ˆ, ํด๋ž˜์Šค๋ฅผ ๊ฐ€์ ธ์˜ค๊ณ  ๋ฐ์ฝ”๋ ˆ์ดํŒ…๋œ ํด๋ž˜์Šค ๋‚ด๋ถ€์—์„œ ์‚ฌ์šฉ๋˜๋Š” ์ƒˆ ๋ฉ”์„œ๋“œ๋กœ ์ƒˆ ํด๋ž˜์Šค๋ฅผ ๋‹ค์‹œ ๋‚ด๋ณด๋‚ด๋Š” ์ธ๊ธฐ ์žˆ๋Š” npm ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์— ๋Œ€ํ•ด ์•Œ์ง€ ๋ชปํ•ฉ๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ ๋‚˜์™€ ๋‹ค๋ฅธ ์‚ฌ๋žŒ๋“ค์ด ์šฐ๋ฆฌ ์ž์‹ ์˜ ๋ฏน์Šค์ธ์„ ๊ตฌํ˜„ํ•˜๊ธฐ ์œ„ํ•ด ์šฐ๋ฆฌ ์ž์‹ ์˜ ์ฝ”๋“œ์—์„œ ์ž์ฃผ ํ•˜๋Š” ์ผ์ด์ง€๋งŒ ์‹ค์ œ๋กœ npm์— ๋Œ€ํ•œ ์˜ˆ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.

๊ทธ๋Ÿฌ๋‚˜ ์ด๊ฒƒ์ด ์ผ๋ฐ˜์ ์ธ ์‚ฌ์šฉ ์‚ฌ๋ก€๋ผ๋Š” ์ ์—์„œ ๋…ผ์Ÿ์˜ ์—ฌ์ง€๊ฐ€ ์—†๋Š” ๊ฒƒ์€ ์•„๋‹™๋‹ˆ๋‹ค. ๊ทธ๋ ‡์ฃ ?

@arackaf ์•„๋‹ˆ์š”, @connect this ์˜ ํšŒ์›์— ์•ก์„ธ์Šคํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ๊ทธ๋ ‡์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์‚ฌ์‹ค ์ €๋Š” ์ด ์ •ํ™•ํ•œ ์Šค๋‹ˆํŽซ์„ ํ™•์‹ ํ•ฉ๋‹ˆ๋‹ค.

@connect(state => state.stuffThatSatisfiesPropsShape)
class Foo extends Component<PropsShape, any> {
    render(){
        this.props.stuffFromPropsShape // <----- added by decorator
    }
}

์˜ค๋Š˜ TypeScript์—์„œ ๋ฌธ์ œ ์—†์ด ์ปดํŒŒ์ผ๋ฉ๋‹ˆ๋‹ค. ๋ถ™์—ฌ๋„ฃ์€ ์Šค๋‹ˆํŽซ์€ ์š”์ฒญํ•œ ๊ธฐ๋Šฅ๊ณผ ์•„๋ฌด ๊ด€๋ จ์ด ์—†์Šต๋‹ˆ๋‹ค.

@masaedu - ์ •๋ง ์ฃ„์†กํ•ฉ๋‹ˆ๋‹ค - ์ œ๊ฐ€ ํ‹€๋ ธ๋‹ค๋Š” ๊ฒƒ์„ ๊นจ๋‹ซ๊ณ  ๊ทธ ๋Œ“๊ธ€์„ ์‚ญ์ œํ–ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ž˜๋„ ์‹œ๊ฐ„ ๋‚ญ๋น„๋ฅผ ๋ฐฉ์ง€ํ•  ๋งŒํผ ๋น ๋ฅด์ง€๋Š” ์•Š์Šต๋‹ˆ๋‹ค. :(

@arackaf ํŒจํ„ด์ด ์–ผ๋งˆ๋‚˜ ํ”ํ•œ์ง€ ๋ชจ๋ฅด๊ฒ ๊ณ  ๊ฐœ์ธ์ ์œผ๋กœ ์ง์ ‘ ์‚ฌ์šฉํ•˜๊ฑฐ๋‚˜ ์‚ฌ์šฉํ•˜๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค. ํ•œ๋™์•ˆ Angular 2๋ฅผ ์‚ฌ์šฉํ–ˆ๊ธฐ ๋•Œ๋ฌธ์— ๋‚ด ์ธ์ƒ์—์„œ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋ฅผ ์‚ฌ์šฉํ•œ ์ ์ด ์—†๋Š” ๊ฒƒ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค. ์ด๊ฒƒ์ด ๋‚ด๊ฐ€ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๊ฐ€ ๋„์ž…ํ•œ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ ๋ฉค๋ฒ„์— ์•ก์„ธ์Šคํ•  ์ˆ˜ ์—†๋Š” ๊ฒƒ์ด ๊ณจ์นซ๊ฑฐ๋ฆฌ์ธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ตฌ์ฒด์ ์ธ ์˜ˆ๋ฅผ ์š”์ฒญํ•œ ์ด์œ ์ž…๋‹ˆ๋‹ค.

ํด๋ž˜์Šค์˜ ๊ตฌ์„ฑ์›์ด this ๋ฅผ ๊ธฐ๋Œ€ํ•˜๋Š” ๋ชจ๋“  ๊ฒฝ์šฐ์— ํด๋ž˜์Šค ๋ณธ๋ฌธ์ด๋‚˜ ํด๋ž˜์Šค์˜ extends ์ ˆ์— ์š”๊ตฌ ์‚ฌํ•ญ์„ ์ถฉ์กฑํ•˜๋Š” ๋ฌด์–ธ๊ฐ€๊ฐ€ ์žˆ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ์—์„œ๋„ ํ•ญ์ƒ ์ž‘๋™ํ•˜๋Š” ๋ฐฉ์‹์ž…๋‹ˆ๋‹ค. ํด๋ž˜์Šค๊ฐ€ ์˜์กดํ•˜๋Š” ์ผ๋ถ€ ๊ธฐ๋Šฅ์„ ์ถ”๊ฐ€ํ•˜๋Š” ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๊ฐ€ ์žˆ๋Š” ๊ฒฝ์šฐ ํด๋ž˜์Šค๋Š” ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๊ฐ€ ๋ฐ˜ํ™˜ํ•˜๋Š” ๋ชจ๋“  ๊ฒƒ์„ ํ™•์žฅํ•ด์•ผ ํ•˜๋ฉฐ ๊ทธ ๋ฐ˜๋Œ€๋Š” ์•ˆ๋ฉ๋‹ˆ๋‹ค. ๊ทธ๋ƒฅ ์ƒ์‹์ž…๋‹ˆ๋‹ค.

์ด๊ฒŒ ์™œ ์ƒ์‹์ธ์ง€ ๋ชจ๋ฅด๊ฒ ์Šต๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ ํ˜„์žฌ ์šฐ๋ฆฌ ์ฝ”๋“œ ๋ฒ ์ด์Šค์˜ ์ฝ”๋“œ์ž…๋‹ˆ๋‹ค. ํด๋ž˜์Šค์˜ ํ”„๋กœํ† ํƒ€์ž…์— ๋ฉ”์„œ๋“œ๋ฅผ ์ถ”๊ฐ€ํ•˜๋Š” ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. TypeScript ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค. ๋‹น์‹œ ๋‚˜๋Š” ์ด ์„ ์–ธ๋ฌธ์„ ๊ฑฐ๊ธฐ์— ๋˜์กŒ๋‹ค. ์ธํ„ฐํŽ˜์ด์Šค ๋ณ‘ํ•ฉ์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.

๊ทธ๋Ÿฌ๋‚˜ ์•„๋ฌด ๊ฒƒ๋„ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค. TypeScript์— "์ด ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋Š” ์ ์šฉ๋˜๋Š” ๋ชจ๋“  ํด๋ž˜์Šค์— ์ด ๋ฉ”์„œ๋“œ๋ฅผ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค. - ํด๋ž˜์Šค ๋‚ด๋ถ€์˜ this ๋„ ์•ก์„ธ์Šคํ•  ์ˆ˜ ์žˆ๋„๋ก ํ—ˆ์šฉํ•ฉ๋‹ˆ๋‹ค"๋ผ๊ณ  ๋งํ•  ์ˆ˜ ์žˆ๋‹ค๋ฉด ์ •๋ง ์ข‹์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์ด ์Šค๋ ˆ๋“œ์˜ ๋‹ค๋ฅธ ๋งŽ์€ ์‚ฌ๋žŒ๋“ค์ด ๋น„์Šทํ•œ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์œผ๋กœ ๋ณด์ด๋ฏ€๋กœ ์ด๊ฒƒ์ด ์ž‘๋™ํ•˜์ง€ ์•Š์•„์•ผ ํ•œ๋‹ค๋Š” ๊ฒƒ์ด ์ƒ์‹์ด ์•„๋‹ ์ˆ˜๋„ ์žˆ์Œ์„ ๊ณ ๋ คํ•˜์‹œ๊ธฐ ๋ฐ”๋ž๋‹ˆ๋‹ค.

image

@arackaf ๋„ค, ๊ทธ๋ž˜์„œ export class SearchVm extends (@mappable({...}) class extends SearchVmBase {}) ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๋งคํ•‘ ๊ฐ€๋Šฅ์„ฑ์— ๋”ฐ๋ผ ๋‹ฌ๋ผ์ง€๋Š” ๊ฒƒ์€ SearchVm ์ด์ง€ ๊ทธ ๋ฐ˜๋Œ€๊ฐ€ ์•„๋‹™๋‹ˆ๋‹ค.

๋‚ด๋ณด๋‚ด๊ธฐ ํด๋ž˜์Šค SearchVm ํ™•์žฅ(@mappable({...}) ํด๋ž˜์Šค ํ™•์žฅ SearchVmBase {})

์ด ์Šค๋ ˆ๋“œ์˜ ์š”์ ์€ ๊ทธ๋Ÿฐ ์ƒ์šฉ๊ตฌ๋ฅผ ํ”ผํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋Š” ๊ทธ๋Ÿฐ ์ผ์„ ํ•˜๋Š” ๊ฒƒ๋ณด๋‹ค ํ›จ์”ฌ ๋” ๋ฉ‹์ง„ DX๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ณด๋‹ค๋Š” ์ €์™€ ๊ฐ™์€ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๊ธฐ๋กœ ์„ ํƒํ•œ ์ด์œ ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

์ด ์Šค๋ ˆ๋“œ์— ๋Œ€ํ•œ ์ฃผ์„์„ ์ฝ์œผ๋ฉด ๋งŽ์€ ๋‹ค๋ฅธ ์‚ฌ๋žŒ๋“ค์ด ๋” ๊ฐ„๋‹จํ•œ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ ๊ตฌ๋ฌธ์„ ์‚ฌ์šฉํ•˜๋ ค๊ณ  ํ•˜๋ฏ€๋กœ ์šฐ๋ฆฌ๊ฐ€ "ํ•ด์•ผ ํ• " ์ผ์ด๋‚˜ "์ƒ์‹" ๋“ฑ์„ ์žฌ๊ณ ํ•˜๋ ค๊ณ  ํ•œ๋‹ค๋Š” ๊ฒƒ์„ ํ™•์‹ ํ•  ์ˆ˜ ์žˆ๊ธฐ๋ฅผ ๋ฐ”๋ž๋‹ˆ๋‹ค.

์›ํ•˜๋Š” ๊ฒƒ์€ ํŠน๋ณ„ํžˆ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ์™€ ๊ด€๋ จ์ด ์—†์Šต๋‹ˆ๋‹ค. ๋ฌธ์ œ๋Š” TypeScript์˜ "์ด๋ด TypeScript, ์ด ๊ตฌ์กฐ์— ๋Œ€ํ•ด ๋‹น์‹ ์ด ์ „ํ˜€ ์•Œ์ง€ ๋ชปํ•˜๋Š” ์ผ์ด ์ผ์–ด๋‚˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ์ด์— ๋Œ€ํ•ด ๋ชจ๋‘ ๋งํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค"๋ผ๊ณ  ๋งํ•˜๋Š” ๋ฉ”์ปค๋‹ˆ์ฆ˜์ด ํ˜„์žฌ ๋„ˆ๋ฌด ์ œํ•œ์ ์ด๋ผ๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ง€๊ธˆ์€ ์ธํ„ฐํŽ˜์ด์Šค ๋ณ‘ํ•ฉ๋งŒ ์žˆ์ง€๋งŒ ํ•จ์ˆ˜๊ฐ€ ์ธ์ˆ˜์— ์ธํ„ฐํŽ˜์ด์Šค ๋ณ‘ํ•ฉ์„ ์ ์šฉํ•  ์ˆ˜ ์žˆ๊ธฐ๋ฅผ ์›ํ•ฉ๋‹ˆ๋‹ค. ์ด๋Š” ์–ด๋–ค ์‹์œผ๋กœ๋“  ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ์™€ ํŠน๋ณ„ํžˆ ๊ด€๋ จ์ด ์—†์Šต๋‹ˆ๋‹ค.

์ง€๊ธˆ์€ ์ธํ„ฐํŽ˜์ด์Šค ๋ณ‘ํ•ฉ๋งŒ ์žˆ์ง€๋งŒ ํ•จ์ˆ˜๊ฐ€ ์ธ์ˆ˜์— ์ธํ„ฐํŽ˜์ด์Šค ๋ณ‘ํ•ฉ์„ ์ ์šฉํ•  ์ˆ˜ ์žˆ๊ธฐ๋ฅผ ์›ํ•ฉ๋‹ˆ๋‹ค. ์ด๋Š” ์–ด๋–ค ์‹์œผ๋กœ๋“  ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ์™€ ํŠน๋ณ„ํžˆ ๊ด€๋ จ์ด ์—†์Šต๋‹ˆ๋‹ค.

ํ™•์ธ. ๊ทธ๋Ÿด ์ˆ˜ ์žˆ์ง€. ๋ณ„๋„์˜ ๋ฌธ์ œ๋ฅผ ์—ด๊ฒ ์Šต๋‹ˆ๊นŒ, ์•„๋‹ˆ๋ฉด ์ด ๋ฌธ์ œ์˜ ์ด๋ฆ„์„ ๋ณ€๊ฒฝํ•˜์‹œ๊ฒ ์Šต๋‹ˆ๊นŒ?

@arackaf ์œ ์ผํ•œ "๋ณด์ผ๋Ÿฌ ํ”Œ๋ ˆ์ดํŠธ"๋Š” ๋‚ด๊ฐ€ class { } ๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค๋Š” ์‚ฌ์‹ค์ž…๋‹ˆ๋‹ค . a) ์–ผ๋งˆ๋‚˜ ๋งŽ์€ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋ฅผ ์‚ฌ์šฉํ•˜๋“  ๊ด€๊ณ„์—†์ด ๊ณ ์ •๋œ 7์ž b) ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋Š” (์•„์ง ) ์ž„์˜์˜ ํด๋ž˜์Šค ๋ฐ˜ํ™˜ ํ‘œํ˜„์‹์— ์ ์šฉ, c) ํŠน๋ณ„ํžˆ ๊ท€ํ•˜์˜ ์ด์ต์„ ์œ„ํ•ด ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์‹ถ์—ˆ๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ์ด ๋Œ€์ฒด ๊ณต์‹:

export class SearchVm extends mappable({...})(SearchVmBase)
{
}

์›๋ž˜ ํ•˜๊ณ  ์žˆ๋Š” ๊ฒƒ๋ณด๋‹ค ๋” ์žฅํ™ฉํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

ํ™•์ธ. ๊ทธ๋Ÿด ์ˆ˜ ์žˆ์ง€. ๋ณ„๋„์˜ ๋ฌธ์ œ๋ฅผ ์—ด๊ฒ ์Šต๋‹ˆ๊นŒ, ์•„๋‹ˆ๋ฉด ์ด ๋ฌธ์ œ์˜ ์ด๋ฆ„์„ ๋ณ€๊ฒฝํ•˜์‹œ๊ฒ ์Šต๋‹ˆ๊นŒ?

๋ณ„๋„์˜ ๋ฌธ์ œ๊ฐ€ ์ข‹์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์›๋ž˜ ํ•˜๊ณ  ์žˆ๋Š” ๊ฒƒ๋ณด๋‹ค ๋” ์žฅํ™ฉํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

๋” ์ด์ƒ ์žฅํ™ฉํ•˜์ง€ ์•Š์ง€๋งŒ ๋งŽ์€ ์‚ฌ๋žŒ๋“ค์ด ๋‹จ์ˆœํžˆ ๊ทธ ๊ตฌ๋ฌธ์„ ์‹ซ์–ดํ•œ๋‹ค๋Š” ์‚ฌ์‹ค์„ ๊ณ ๋ คํ•˜๊ธฐ๋ฅผ ๋ฐ”๋ž๋‹ˆ๋‹ค. ์ข‹๋“  ๋‚˜์˜๋“  ๋งŽ์€ ์‚ฌ๋žŒ๋“ค์ด DX ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๊ฐ€ ์ œ๊ณตํ•˜๋Š” ๊ฒƒ์„ ์„ ํ˜ธํ•ฉ๋‹ˆ๋‹ค.

๋ณ„๋„์˜ ๋ฌธ์ œ๊ฐ€ ์ข‹์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๋‚ด์ผ ํ•˜๋‚˜๋ฅผ ์ž…๋ ฅํ•˜๊ณ  ์ปจํ…์ŠคํŠธ๋ฅผ ์œ„ํ•ด ์ด ๋งํฌ์— ์—ฐ๊ฒฐํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

์ด ์ž‘์—…์„ ๋„์™€์ฃผ์…”์„œ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค. :)

๋‚ด๊ฐ€ ๋“ค์–ด๊ฐˆ ์ˆ˜ ์žˆ๋‹ค๋ฉด, @masaeedu ๋‚˜๋Š” ์ด ์ง„์ˆ ์— ๋™์˜ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค:

์›ํ•˜๋Š” ๊ฒƒ์€ ํŠน๋ณ„ํžˆ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ์™€ ๊ด€๋ จ์ด ์—†์Šต๋‹ˆ๋‹ค. ๋ฌธ์ œ๋Š” TypeScript์˜ "์ด๋ด TypeScript, ์ด ๊ตฌ์กฐ์— ๋Œ€ํ•ด ๋‹น์‹ ์ด ์ „ํ˜€ ์•Œ์ง€ ๋ชปํ•˜๋Š” ์ผ์ด ์ผ์–ด๋‚˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ์ด์— ๋Œ€ํ•ด ๋ชจ๋‘ ๋งํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค"๋ผ๊ณ  ๋งํ•˜๋Š” ๋ฉ”์ปค๋‹ˆ์ฆ˜์ด ํ˜„์žฌ ๋„ˆ๋ฌด ์ œํ•œ์ ์ด๋ผ๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ง€๊ธˆ์€ ์ธํ„ฐํŽ˜์ด์Šค ๋ณ‘ํ•ฉ๋งŒ ์žˆ์ง€๋งŒ ํ•จ์ˆ˜๊ฐ€ ์ธ์ˆ˜์— ์ธํ„ฐํŽ˜์ด์Šค ๋ณ‘ํ•ฉ์„ ์ ์šฉํ•  ์ˆ˜ ์žˆ๊ธฐ๋ฅผ ์›ํ•ฉ๋‹ˆ๋‹ค. ์ด๋Š” ์–ด๋–ค ์‹์œผ๋กœ๋“  ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ์™€ ํŠน๋ณ„ํžˆ ๊ด€๋ จ์ด ์—†์Šต๋‹ˆ๋‹ค.

ํ™•์‹คํžˆ TypeScript๋Š” ํด๋ž˜์Šค ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ์˜ ๋ฐ˜ํ™˜ ์œ ํ˜• ์„ ๋ณด๊ณ  ๋Œ์—ฐ๋ณ€์ด๋œ ํด๋ž˜์Šค๊ฐ€ ์–ด๋–ค ์œ ํ˜•์ด์–ด์•ผ ํ•˜๋Š”์ง€ ์•Œ์•„๋‚ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. "์ธ์ˆ˜์— ์ธํ„ฐํŽ˜์ด์Šค ๋ณ‘ํ•ฉ ์ ์šฉ"์ด ํ•„์š”ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋‚ด๊ฐ€ ๋ณด๊ธฐ์— ๊ทธ๊ฒƒ์€ ์ „์ ์œผ๋กœ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ์™€ ๊ด€๋ จ์ด ์žˆ์Šต๋‹ˆ๋‹ค.

๋˜ํ•œ ์—ฐ๊ฒฐ๋œ ๊ตฌ์„ฑ ์š”์†Œ์— ๋” ์ด์ƒ props๊ฐ€ ํ•„์š”ํ•˜์ง€ ์•Š๋‹ค๋Š” ๊ฒƒ์„ TypeScript๊ฐ€ ์•Œ์ง€ ๋ชปํ•˜๋Š” ๊ฒฝ์šฐ๋Š” React ๋ฐ TypeScript์™€ ํ•จ๊ป˜ Redux๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์„ ๊บผ๋ฆฌ๊ฒŒ ํ•œ ์ธก๋ฉด ์ค‘ ํ•˜๋‚˜์ž…๋‹ˆ๋‹ค.

@codeandcats ์“ฐ๋ ˆ๋“œ๊ฐ€ ์‹œ์ž‘๋œ ์ดํ›„๋กœ ๋‚˜๋Š” ์ด๊ฒƒ๊ณผ ํ•จ๊ป˜ ์„œํด์— ๋“ค์–ด๊ฐ€๊ณ  ์žˆ์œผ๋ฉฐ ๋” ์ด์ƒ ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ์•ž์˜ ํ† ๋ก ์„ ์ฃผ์˜ ๊นŠ๊ฒŒ ์‚ดํŽด๋ณด๊ณ  ์‹ค์ œ๋กœ ๋‚ด๊ฐ€ @arackaf ์— ๋Œ€ํ•ด ๋™์˜ํ•˜์ง€ ์•Š๋Š” ๋ถ€๋ถ„์„ ์ดํ•ดํ•˜๋ ค๊ณ  ๋…ธ๋ ฅํ•˜์‹ญ์‹œ์˜ค.

<strong i="8">@bar</strong> class Foo { } ์„ ํ•  ๋•Œ Foo ์˜ ์œ ํ˜•์€ bar ์˜ ๋ฐ˜ํ™˜ ์œ ํ˜•์ด์–ด์•ผ ํ•œ๋‹ค๋Š” ๋ฐ ๋™์˜ํ•ฉ๋‹ˆ๋‹ค. Foo this #$๊ฐ€ ์–ด๋–ค ์‹์œผ๋กœ๋“  ์˜ํ–ฅ์„ ๋ฐ›์•„์•ผ ํ•œ๋‹ค๋Š” ๋ฐ ๋™์˜ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. connect ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์€ ์—ฌ๊ธฐ์„œ ๊ฒฝํ•ฉ์˜ ์š”์ ๊ณผ ์ „ํ˜€ ๊ด€๋ จ์ด ์—†์Šต๋‹ˆ๋‹ค. ์™œ๋ƒํ•˜๋ฉด connect ๋Š” ์žฅ์‹๋œ ๊ตฌ์„ฑ ์š”์†Œ๊ฐ€ ํ”„๋กœํ† ํƒ€์ž…์— ์ถ”๊ฐ€ํ•˜๋Š” ๋ฉค๋ฒ„๋ฅผ ์ธ์‹ํ•˜๊ณ  ์‚ฌ์šฉํ•  ๊ฒƒ์œผ๋กœ ๊ธฐ๋Œ€ํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

๋‚˜๋Š” ๋‹น์‹ ์ด @masaeedu ์— ์ขŒ์ ˆํ–ˆ๋‹ค๋Š” ๊ฒƒ์„ ์ดํ•ดํ•  ์ˆ˜ ์žˆ์ง€๋งŒ, ๋‚ด๊ฐ€ ์ด ์•ž๋’ค๋กœ ์ ๊ทน์ ์œผ๋กœ ๋‚ด ์˜๊ฒฌ์„ ํ‘œ๋ช…ํ•˜์ง€ ์•Š์•˜๋‹ค๊ณ  ํ•ด์„œ ์ง€๋‚œ 48์‹œ๊ฐ„ ๋™์•ˆ ๋‚ด๊ฐ€ ํ† ๋ก ์„ ํŒ”๋กœ์šฐํ•˜์ง€ ์•Š์•˜๋‹ค๊ณ  ์ƒ๊ฐํ•˜์ง€ ๋งˆ์‹ญ์‹œ์˜ค - ๊ทธ๋Ÿฌ๋‹ˆ ์ œ๋ฐœ ๊ฒธ์†ํ•œ ์นœ๊ตฌ๋ฅผ ์‚ด๋ ค์ฃผ์„ธ์š”.

๋‚ด๊ฐ€ ์ดํ•ดํ•˜๋Š” ํ•œ, ๋‹น์‹ ์€ ๋ฐ์ฝ”๋ ˆ์ดํŒ…๋œ ํด๋ž˜์Šค ๋‚ด๋ถ€์—์„œ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ์— ์˜ํ•ด ์ž์ฒด์ ์œผ๋กœ ๋งŒ๋“ค์–ด์ง„ ๋Œ์—ฐ๋ณ€์ด์— ๋Œ€ํ•ด ์•Œ๋ฉด ์•ˆ ๋œ๋‹ค๊ณ  ์ƒ๊ฐํ•˜์ง€๋งŒ ์™ธ๋ถ€์—์„œ๋Š” ์•Œ์•„์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๋‚˜๋Š” ๊ทธ๊ฒƒ์— ๋™์˜ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. @arackaf ๊ฐ€ ํด๋ž˜์Šค ๋‚ด๋ถ€์—์„œ ๋ณ€ํ˜•๋œ ๋ฒ„์ „์„ ๋ด์•ผ ํ•œ๋‹ค๊ณ  ์ƒ๊ฐํ•œ๋‹ค๋Š” ์‚ฌ์‹ค์€ ๋‚ด ์˜๊ฒฌ์˜ ์š”์ง€์™€ ๋‹ค๋ฆ…๋‹ˆ๋‹ค.

์–ด๋Š ์ชฝ์ด๋“  TypeScript๋Š” ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ ํ•จ์ˆ˜์—์„œ ๋ฐ˜ํ™˜๋œ ์œ ํ˜•์„ ํด๋ž˜์Šค์˜ ์ •๋ณด ์†Œ์Šค๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ์ด๊ฒƒ์€ ๋‹น์‹ ์ด ์ œ์•ˆํ•œ ๊ฒƒ์ฒ˜๋Ÿผ ์ƒˆ๋กœ์šด ๊ธฐ๊ดดํ•œ ์ธ์ˆ˜ ๋Œ์—ฐ๋ณ€์ด ๊ธฐ๋Šฅ์ด ์•„๋‹ˆ๋ผ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ ๋ฌธ์ œ์ž…๋‹ˆ๋‹ค.

@Zalastax ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ ๊ธฐ๋Šฅ์„ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๊ฐ€ ์•„๋‹Œ ํ•จ์ˆ˜๋กœ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ์ ์šฉํ•ด์•ผ ํ•˜๋Š” ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๊ฐ€ ์—ฌ๋Ÿฌ ๊ฐœ์ธ ๊ฒฝ์šฐ ์ค‘์ฒฉํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ด๋Š” ๊ธฐ์ˆ ์ ์œผ๋กœ ๋” ์ด์ƒ ์žฅํ™ฉํ•˜์ง€ ์•Š์ง€๋งŒ ๊ตฌ๋ฌธ์ ์œผ๋กœ๋Š” ์ฆ๊ฒ์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋ฌด์Šจ ๋ง์ธ์ง€ ์•„์‹ญ๋‹ˆ๊นŒ?

๊ฒธ์† ๋“ฑ

์†Œ์Œ.

@arackaf ๊ฐ€ ํด๋ž˜์Šค ๋‚ด๋ถ€์—์„œ ๋ณ€ํ˜•๋œ ๋ฒ„์ „์„ ๋ด์•ผ ํ•œ๋‹ค๊ณ  ์ƒ๊ฐํ•œ๋‹ค๋Š” ์‚ฌ์‹ค์€ ๋‚ด ์˜๊ฒฌ์˜ ์š”์ง€์™€ ๋‹ค๋ฆ…๋‹ˆ๋‹ค.

๊ทธ๊ฒƒ์€ ๋‹น์‹ ์ด ์‘๋‹ตํ•˜๊ณ  ์žˆ๋Š” ๋‹จ๋ฝ์˜ ์ค‘์‹ฌ์ ์ด๋ฏ€๋กœ, ๋‹น์‹ ์ด ๋‹ค๋ฅธ ๊ฒƒ์— ๋Œ€ํ•ด ์ด์•ผ๊ธฐํ•˜๊ณ  ์žˆ๋‹ค๋ฉด ๊ทธ๊ฒƒ์€ ๋ถ€์ ์ ˆํ•ฉ๋‹ˆ๋‹ค. @arackaf ๊ฐ€ ์›ํ•˜๋Š” ๊ฒƒ์€ ๋Œ€๋žต์ ์œผ๋กœ ํ•จ์ˆ˜ ์ธ์ˆ˜์— ๋Œ€ํ•œ ์ธํ„ฐํŽ˜์ด์Šค ๋ณ‘ํ•ฉ์ž…๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ์™€ ๋…๋ฆฝ์ ์ธ ๊ธฐ๋Šฅ์œผ๋กœ ๋” ์ž˜ ํ•ด๊ฒฐ๋ฉ๋‹ˆ๋‹ค. ๋‹น์‹ ์ด ์›ํ•˜๋Š” ๊ฒƒ์€ (๋‚ด๊ฐ€ ์›ํ•˜๋Š” ๊ฒƒ๊ณผ ๋ถ„๋ช…ํžˆ ๋™์ผํ•จ) <strong i="12">@foo</strong> class Foo { } ๊ฐ€ Foo ์— ๋Œ€ํ•ด const Foo = foo(class { }) ์™€ ๊ฐ™์€ ์œ ํ˜• ์„œ๋ช…์„ ์ƒ์„ฑํ•˜์ง€ ์•Š๋Š” TypeScript์˜ ๋ฒ„๊ทธ๋ฅผ ์ˆ˜์ •ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๋‚ด๊ฐ€ ์ดํ•ดํ•˜๋Š” ํ•œ, ๋‹น์‹ ์€ ๋ฐ์ฝ”๋ ˆ์ดํŒ…๋œ ํด๋ž˜์Šค ๋‚ด๋ถ€์—์„œ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ์— ์˜ํ•ด ์ž์ฒด์ ์œผ๋กœ ๋งŒ๋“ค์–ด์ง„ ๋Œ์—ฐ๋ณ€์ด์— ๋Œ€ํ•ด ์•Œ๋ฉด ์•ˆ ๋œ๋‹ค๊ณ  ์ƒ๊ฐํ•˜์ง€๋งŒ ์™ธ๋ถ€์—์„œ๋Š” ์•Œ์•„์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๋‚˜๋Š” ๊ทธ๊ฒƒ์— ๋™์˜ํ•˜์ง€ ์•Š๋Š”๋‹ค

์šฐ๋ฆฌ๊ฐ€ ๋™์˜ํ•˜๋Š” ๊ฒƒ์— ๋Œ€ํ•ด ์ด์•ผ๊ธฐํ•˜๊ธฐ๋กœ ๊ฒฐ์ •ํ–ˆ์ง€๋งŒ "๋‚˜๋Š” ์ด ์ง„์ˆ ์— ๋™์˜ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค"๋กœ ์‹œ์ž‘ํ•œ๋‹ค๋ฉด, ๋‹น์‹ ์€ ์‹œ๊ฐ„ ๋‚ญ๋น„์ผ ๋ฟ์ž…๋‹ˆ๋‹ค.

์ด ์†Œ๊ธˆ์œผ๋กœ ๊ฐ์ž ํŠ€๊น€์„ ๋จน์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ?

์•„, ์•Œ๊ฒ ์Šต๋‹ˆ๋‹ค. ๋™๋ฃŒ๋ฅผ ์• ์šฉํ•˜๋Š” ๊ฒƒ์€ ๋ฒŒ๊ธˆ์ด์ง€๋งŒ ์‚ฌ๋žŒ๋“ค์ด ๋‹น์‹ ์„ ๋Œ์–ด๋“ค์ธ๋‹ค๋ฉด ๊ทธ๊ฒƒ์€ ์†Œ์Œ์ž…๋‹ˆ๋‹ค.

@arackaf๊ฐ€ ์ œ์•ˆํ•œ ๊ฒƒ์„ ๊ตฌํ˜„ํ•˜๊ธฐ ์œ„ํ•ด "์ธ์ˆ˜ ๋Œ์—ฐ๋ณ€์ด" ๊ฐœ๋…์ด ํ•„์š”ํ•œ ์ด์œ ๋ฅผ ๋ชจ๋ฅด๊ฒ ์Šต๋‹ˆ๋‹ค.

์šฐ๋ฆฌ๊ฐ€ @arackaf ์— ๋™์˜ํ•˜๋Š”์ง€ ์—ฌ๋ถ€์— ๊ด€๊ณ„์—†์ด ๋‚ด ๊ฒธ์†ํ•œ ์˜๊ฒฌ์œผ๋กœ๋Š” TypeScript๊ฐ€ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ ๊ฒฐ๊ณผ์—์„œ ์‹ค์ œ ์œ ํ˜•์„ ๋‹จ์ˆœํžˆ ์ถ”๋ก ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ˆ˜์น˜์‹ฌ์„ ๋Š๋ผ์…จ๋‹ค๋ฉด ์‚ฌ๊ณผ๋“œ๋ฆฝ๋‹ˆ๋‹ค. ์˜๋„๋Š” ๋‹น์‹ ์„ ์–ป๋Š” ๊ฒƒ์ด ์—ˆ์Šต๋‹ˆ๋‹ค.
์‚ฌ์‹ค ๋ˆ„๊ตฌ๋‚˜ ์šฉ์„œํ•  ์ˆ˜ ์žˆ๋Š” ๊ฑฐ๋Œ€ํ•œ ์—‰์„ฑํ•œ ์‹ค
์Šคํ‚ค๋ฐ. ๋‹น์‹ ์ด ์ธ์‹ํ•˜์ง€ ๋ชปํ•˜๋Š” ๊ฒƒ์ด ์—ฌ์ „ํžˆ ๋งค์šฐ ๋ถ„๋ช…ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋‚˜๋Š” ์ด๊ฒƒ์„ ์ง€์ง€ํ•ฉ๋‹ˆ๋‹ค
์— ๋Œ€ํ•œ ์˜คํ•ด๋กœ ์ธํ•ด ๋‚˜์™€ "๋™์˜ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค".
๋‚ด ์œ„์น˜.

์˜ˆ๋ฅผ ๋“ค์–ด, ์ธํ„ฐํŽ˜์ด์Šค๊ฐ€ ํ•จ์ˆ˜์— ๋ณ‘ํ•ฉ๋˜๋Š” ์ด์œ ์— ๋Œ€ํ•œ ๊ท€ํ•˜์˜ ์งˆ๋ฌธ
์ฃผ์žฅ์€ ์•„๋‹ด์˜ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๋Š” ๊ฐ€์žฅ ์ข‹์€ ๋ฐฉ๋ฒ•์€ ๊ด€๋ จ ํ•ญ๋ชฉ์„ ์‚ดํŽด๋ณด๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.
Adam๊ณผ์˜ ํ† ๋ก ์—์„œ ๊ทธ๋Š” ์ด๋ฏธ ์ธํ„ฐํŽ˜์ด์Šค ๋ณ‘ํ•ฉ์„ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๋‹ค๊ณ  ๋งํ•ฉ๋‹ˆ๋‹ค.
๊ทธ๋Ÿฌ๋‚˜ ๊ฐ ์„ ์–ธ ์‚ฌ์ดํŠธ์—์„œ ์ด ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•ด์•ผ ํ•˜๋Š” ๊ฒƒ์€ ์„ฑ๊ฐ€์‹  ์ผ์ž…๋‹ˆ๋‹ค.

๋‚˜๋Š” ์ด๊ฒƒ์˜ ๋ชจ๋“  ๊ธฐ์ˆ ์  ์ธก๋ฉด์ด ์ฃฝ๋„๋ก ๋‘๋“ค๊ฒจ ๋งž์•˜๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ๋‚˜
์Šค๋ ˆ๋“œ๊ฐ€ ๋Œ€์ธ ๋ฌธ์ œ์— ์˜ํ•ด ์ง€๋ฐฐ๋˜๋Š” ๊ฒƒ์„ ์›ํ•˜์ง€ ์•Š์œผ๋ฏ€๋กœ ์ด๊ฒƒ์€
๋‚ด ๋งˆ์ง€๋ง‰ ๊ฒŒ์‹œ๋ฌผ์ด ๋  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์‚ฌ์‹ค, ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ์—๋Š” ๋‘ ๊ฐ€์ง€ ๋ฒ„๊ทธ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ๋ฐ˜ํ™˜ ์œ ํ˜•์ด ์กด์ค‘๋˜์ง€ ์•Š๊ณ  ํด๋ž˜์Šค ๋‚ด๋ถ€์—์„œ ์ถ”๊ฐ€๋œ ๋ฉค๋ฒ„๊ฐ€ ์กด์ค‘๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค(ํด๋ž˜์Šค ๋‚ด๋ถ€ this ). ๊ทธ๋ฆฌ๊ณ  ์˜ˆ, ์ „์ž๊ฐ€ ๋” ์‰ฝ๊ฒŒ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ํ›„์ž์— ๋” ๊ด€์‹ฌ์ด ์žˆ์Šต๋‹ˆ๋‹ค.

์—ฌ๊ธฐ์— ๋ณ„๋„์˜ ์ผ€์ด์Šค๋ฅผ ์—ด์—ˆ์Šต๋‹ˆ๋‹ค. https://github.com/Microsoft/TypeScript/issues/16599

์•ˆ๋…•ํ•˜์„ธ์š” ์—ฌ๋Ÿฌ๋ถ„, ์ €๋Š” ์ฃผ๋ง ๋™์•ˆ ์ด ๋Œ€ํ™”๋ฅผ ๋†“์ณค์Šต๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์•„๋งˆ๋„ ์ง€๊ธˆ ๋‹ค์‹œ ๊ฐ€์ ธ์˜ฌ ์ด์œ ๊ฐ€ ๋งŽ์ง€ ์•Š์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๋‚˜๋Š” ์ด๋Ÿฌํ•œ ์ข…๋ฅ˜์˜ ํ† ๋ก ์ด ๋œจ๊ฒ๋‹ค๋Š” ๊ฒƒ์„ ๋ชจ๋‘์—๊ฒŒ ์ƒ๊ธฐ์‹œํ‚ค๊ณ  ์‹ถ์Šต๋‹ˆ๋‹ค. ์ผ๋ฐ˜์ ์œผ๋กœ ์ฐธ์—ฌํ•˜๋Š” ๋ชจ๋“  ์‚ฌ๋žŒ์€ ์„ ์˜์ž…๋‹ˆ๋‹ค. ์ •์ค‘ํ•œ ์–ด์กฐ๋ฅผ ์œ ์ง€ํ•˜๋ฉด ๋Œ€ํ™”๋ฅผ ๋ช…ํ™•ํ•˜๊ฒŒ ํ•˜๊ณ  ๋ฐฉํ–ฅ์„ ์žก๋Š” ๋ฐ ๋„์›€์ด ๋˜๋ฉฐ ์ƒˆ๋กœ์šด ์ฐธ์—ฌ์ž๋ฅผ ์œก์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋ ‡๊ฒŒ ํ•˜๋Š” ๊ฒƒ์ด ํ•ญ์ƒ ์‰ฌ์šด ๊ฒƒ์€ ์•„๋‹ˆ์ง€๋งŒ(ํŠนํžˆ ์ธํ„ฐ๋„ท์ด ๋…์ž์—๊ฒŒ ์ƒ‰์กฐ๋ฅผ ๋งก๊ธธ ๋•Œ), ๋ฏธ๋ž˜ ์‹œ๋‚˜๋ฆฌ์˜ค์—์„œ๋Š” ์ด๊ฒƒ์ด ์ค‘์š”ํ•˜๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ๐Ÿ˜ƒ

์ด์— ๋Œ€ํ•œ ์ƒํƒœ๋Š” ์–ด๋–ป์Šต๋‹ˆ๊นŒ?

@alex94puchades ์•„์ง 2๋‹จ๊ณ„ ์ œ์•ˆ ์ด๋ฏ€๋กœ ์•„์ง ์‹œ๊ฐ„์ด ์ข€ ๋‚จ์•„ ์žˆ์Šต๋‹ˆ๋‹ค. TC39๋Š” ์ ์–ด๋„ ์•ฝ๊ฐ„์˜ ์›€์ง์ž„์ด ์žˆ๋Š” ๊ฒƒ์œผ๋กœ ๋ณด์ž…๋‹ˆ๋‹ค .

์ด ์˜๊ฒฌ ์— ๋”ฐ๋ฅด๋ฉด ๋น ๋ฅด๋ฉด 11์›”์— 3๋‹จ๊ณ„๋ฅผ ์ œ์•ˆํ•  ์ˆ˜ ์žˆ์„ ๊ฒƒ์œผ๋กœ ๋ณด์ž…๋‹ˆ๋‹ค.

๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋กœ ํ•จ์ˆ˜ ์„œ๋ช…์„ ๋ณ€๊ฒฝํ•˜๋Š” ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•

๋นˆ ์™€ํผ ํ•จ์ˆ˜ ์ถ”๊ฐ€

export default function wapper (cb: any) {
    return cb;
}

์ •์˜ ์ถ”๊ฐ€

export function wapper(cb: IterableIterator<0>): Promise<any>;

๊ฒฐ๊ณผ

<strong i="13">@some</strong> decorator // run generator and return promise
function *abc() {}

wapper(abc()).then() // valid

/ํ•‘

๋ˆ„๊ตฐ๊ฐ€ ์ด๊ฒƒ์— ๋Œ€ํ•œ ํ•ด๊ฒฐ์ฑ…์„ ์ฐพ๊ณ  ์žˆ๋‹ค๋ฉด ๋‚ด๊ฐ€ ์ƒ๊ฐํ•ด๋‚ธ ํ•œ ๊ฐ€์ง€ ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•์ด ์•„๋ž˜์— ์žˆ์Šต๋‹ˆ๋‹ค.

์ค‘์ฒฉ๋œ ๊ฐœ์ฒด๊ฐ€ ํ•„์š”ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ตœ์ƒ์˜ ์†”๋ฃจ์…˜์€ ์•„๋‹ˆ์ง€๋งŒ ์‹ค์ œ๋กœ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ์˜ ์†์„ฑ์ด ํด๋ž˜์Šค ์ธ์Šคํ„ด์Šค์˜ ํ‰๋ฉด์ด ์•„๋‹ˆ๋ผ ๊ฐœ์ฒด์— ์žˆ๊ธฐ๋ฅผ ์›ํ–ˆ๊ธฐ ๋•Œ๋ฌธ์— ์ž˜ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค.

์ด๊ฒƒ์€ ๋‚ด๊ฐ€ Angular 5 ๋ชจ๋‹ฌ์— ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์‚ฌ์šฉ์ž ์ •์˜ ConfirmModalComponent ์— ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” @ModalParams(...) ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๊ฐ€ ์žˆ๋‹ค๊ณ  ๊ฐ€์ •ํ•ฉ๋‹ˆ๋‹ค. @ModalParams(...) ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ์˜ ์†์„ฑ์„ ๋‚ด ์‚ฌ์šฉ์ž ์ง€์ • ๊ตฌ์„ฑ ์š”์†Œ์— ํ‘œ์‹œํ•˜๋ ค๋ฉด ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๊ฐ€ ๊ฐ’์„ ํ• ๋‹นํ•  ์†์„ฑ์ด ์žˆ๋Š” ๊ธฐ๋ณธ ํด๋ž˜์Šค๋ฅผ ํ™•์žฅํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด:

export class Modal {
    params: any;

    constructor(values: Object = {}) {
        Object.assign(this, values);
    }
}

export function ModalParams (params?: any) {
    return (target: any): void  => {
        Object.assign(target.prototype, {
            params: params
        });
    };
}

@Component({...})
@ModalOptions({...})
@ModalParams({
    width:             <number> 300,
    title:             <string> 'Confirm',
    message:           <string> 'Are you sure?',
    confirmButtonText: <string> 'Yes',
    cancelButtonText:  <string> 'No',
    onConfirm:         <(modal: ConfirmModalComponent) => void> (() => {}),
    onCancel:          <(modal: ConfirmModalComponent) => void> (() => {})
})
export class ConfirmModalComponent extends Modal {
    constructor() {
        super();
    }

    confirm() {
        this.params.onConfirm(this); // This does not show a syntax error 
    }

    cancel() {
        this.params.onCancel(this); // This does not show a syntax error 
    }
}

๋‹ค์‹œ ๋งํ•˜์ง€๋งŒ, ๊ทธ๊ฒƒ์€ ๋งค์šฐ ์•„๋ฆ„๋‹ต์ง€๋Š” ์•Š์ง€๋งŒ ๋‚ด ์‚ฌ์šฉ ์‚ฌ๋ก€์— ์ž˜ ์ž‘๋™ํ•˜๋ฏ€๋กœ ๋‹ค๋ฅธ ์‚ฌ๋žŒ์ด ์œ ์šฉํ•˜๋‹ค๊ณ  ์ƒ๊ฐํ–ˆ์Šต๋‹ˆ๋‹ค.

@lansana ํ•˜์ง€๋งŒ ์œ ํ˜•์„ ์–ป์ง€ ๋ชปํ•ฉ๋‹ˆ๊นŒ?

@confraria ๋ถˆํ–‰ํžˆ๋„ ๊ทธ๋ ‡์ง€๋Š” ์•Š์ง€๋งŒ ํ™•์žฅํ•˜๋Š” ์ผ๋ฐ˜ Modal ํด๋ž˜์Šค๋ฅผ ๊ตฌํ˜„ํ•˜๋ฉด ์ด๋ฅผ ๋‹ฌ์„ฑํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์ด ์žˆ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๊ฒƒ์ด ์ž‘๋™ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค(ํ…Œ์ŠคํŠธ๋˜์ง€ ์•Š์Œ).

export class Modal<T> {
    params: T;
}

export function ModalParams (params?: any) {
    return (target: any): void  => {
        Object.assign(target.prototype, {
            params: params
        });
    };
}

// The object in @ModalParams() should be of type MyType
@ModalParams({...})
export class ConfirmModalComponent extends Modal<MyType> {
    constructor() {
        super();
    }
}

:/ ๋„ค, ํ•˜์ง€๋งŒ ์œ ํ˜•์ด ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ์—์„œ ๋ถ„๋ฆฌ๋˜๊ณ  ํ™•์‹คํžˆ ๋‘˜ ์ค‘ ๋‘ ๊ฐœ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.:(๊ฒŒ๋‹ค๊ฐ€ ํด๋ž˜์Šค๊ฐ€ ๋ฉ”์„œ๋“œ๋ฅผ ๊ตฌํ˜„ํ•˜์ง€ ์•Š์œผ๋ฉด ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค. ํ˜„์žฌ ์ด ํŒจํ„ด์— ๋งž๋Š” ์œ ํ˜•์„ ์–ป๋Š” ๋ฐฉ๋ฒ•์ž…๋‹ˆ๋‹ค.

์˜ˆ, ์ด๊ฒƒ์ด ๊ฐ€๋Šฅํ•˜๋ฉด TypeScript๋ฅผ ํ›จ์”ฌ ๋” ํ›Œ๋ฅญํ•˜๊ณ  ํ‘œํ˜„๋ ฅ ์žˆ๊ฒŒ ๋งŒ๋“ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋ฐ”๋ผ๊ฑด๋Œ€ ๊ณง ๋ฌด์–ธ๊ฐ€๊ฐ€ ์˜ฌ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

@lansana ์˜ˆ, ์š”์ ์€ ํด๋ž˜์Šค ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๊ฐ€ ํด๋ž˜์Šค๊ฐ€ ๋‹ค๋ฅธ ๊ฒƒ์„ ํ™•์žฅํ•˜๊ฑฐ๋‚˜ ๊ตฌํ˜„ํ•  ํ•„์š” ์—†์ด ์ž์ฒด์ ์œผ๋กœ ํด๋ž˜์Šค์˜ ์„œ๋ช…์„ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ์œผ๋ฉด ์ข‹์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค(๋…ธ๋ ฅ๊ณผ ์œ ํ˜• ์ •๋ณด์˜ ์ค‘๋ณต์ด๊ธฐ ๋•Œ๋ฌธ์—) .

์ฐธ๊ณ  ์‚ฌํ•ญ: ๊ท€ํ•˜์˜ ์˜ˆ์ œ์—์„œ params ๋Š” ๊ฐœ์ฒด ์ฐธ์กฐ์ด๊ธฐ ๋•Œ๋ฌธ์— ์žฅ์‹๋œ ๋ชจ๋‹ฌ ๊ตฌ์„ฑ ์š”์†Œ ํด๋ž˜์Šค์˜ ๋ชจ๋“  ์ธ์Šคํ„ด์Šค์—์„œ ์ •์ ์ผ ์ˆ˜ ์žˆ๋‹ค๋Š” ์ ์— ์œ ์˜ํ•˜์‹ญ์‹œ์˜ค. ๋น„๋ก ๊ทธ๊ฒƒ์ด ์˜๋„ํ•œ ๊ฒƒ์ผ ์ˆ˜๋„ ์žˆ์ง€๋งŒ. : - ) ํ•˜์ง€๋งŒ ๋‚˜๋Š” ๋น—๋‚˜๊ฐ„๋‹ค...

ํŽธ์ง‘: ์ด๊ฒƒ์— ๋Œ€ํ•ด ์ƒ๊ฐํ•˜๋ฉด์„œ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๊ฐ€ ํด๋ž˜์Šค ์„œ๋ช…์„ ์ˆ˜์ •ํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•˜๋Š” ๊ฒƒ์˜ ๋‹จ์ ์„ ์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํด๋ž˜์Šค ๊ตฌํ˜„์— ํŠน์ • ์œ ํ˜• ์ฃผ์„์ด ๋ถ„๋ช…ํžˆ ํฌํ•จ๋˜์–ด ์žˆ์ง€๋งŒ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๊ฐ€ ์ด ๋ชจ๋“  ๊ฒƒ์„ ๊ธ‰์Šตํ•˜๊ณ  ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ๋‹ค๋ฉด ๊ฐœ๋ฐœ์ž์—๊ฒŒ ์•ฝ๊ฐ„์˜ ๋น„์—ดํ•œ ํŠธ๋ฆญ์ด ๋  ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋งŽ์€ ์‚ฌ์šฉ ์‚ฌ๋ก€๋Š” ๋ถ„๋ช…ํžˆ ์ƒˆ ํด๋ž˜์Šค ๋…ผ๋ฆฌ๋ฅผ ํ†ตํ•ฉํ•˜๋Š” ๊ฒƒ๊ณผ ๊ด€๋ จ์ด ์žˆ์œผ๋ฏ€๋กœ ๋ถˆํ–‰ํžˆ๋„ ๋Œ€๋ถ€๋ถ„์€ ํ™•์žฅ ๋˜๋Š” ์ธํ„ฐํŽ˜์ด์Šค ๊ตฌํ˜„์„ ํ†ตํ•ด ๋” ์‰ฝ๊ฒŒ ์ด‰์ง„๋  ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋˜ํ•œ ๊ธฐ์กด ํด๋ž˜์Šค ์„œ๋ช…๊ณผ ์กฐ์ •๋˜๊ณ  ์ถฉ๋Œ์ด ๋ฐœ์ƒํ•˜๋Š” ๊ฒฝ์šฐ ์ ์ ˆํ•œ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค. Angular์™€ ๊ฐ™์€ ํ”„๋ ˆ์ž„์›Œํฌ๋Š” ๋ฌผ๋ก  ํด๋ž˜์Šค๋ฅผ ๋ณด๊ฐ•ํ•˜๊ธฐ ์œ„ํ•ด ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋ฅผ ๋งŽ์ด ์‚ฌ์šฉํ•˜์ง€๋งŒ ๋””์ž์ธ์€ ํด๋ž˜์Šค๊ฐ€ ์ž์ฒด ๊ตฌํ˜„์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋กœ๋ถ€ํ„ฐ ์ƒˆ๋กœ์šด ๋กœ์ง์„ "์–ป๊ฑฐ๋‚˜" ํ˜ผํ•ฉํ•˜๋„๋ก ํ—ˆ์šฉํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ํ”„๋ ˆ์ž„์›Œํฌ ์กฐ์ • ๋…ผ๋ฆฌ์˜ ํด๋ž˜์Šค ๋…ผ๋ฆฌ. ๊ทธ๊ฒƒ์€ ์–ด์จŒ๋“  ๋‚˜์˜ _๊ฒธ์†ํ•œ_ ์˜๊ฒฌ์ž…๋‹ˆ๋‹ค. : - )

๋ฐ์ฝ”๋ ˆ์ดํ„ฐ + ํ•ต๋ณด๋‹ค๋Š” ๊ณ ์ฐจ ํด๋ž˜์Šค๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ๋” ๋‚˜์€ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. ๋‚˜๋Š” ์‚ฌ๋žŒ๋“ค์ด ์ด ๋ฌผ๊ฑด์— ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์‹ถ์–ดํ•œ๋‹ค๋Š” ๊ฒƒ์„ ์•Œ๊ณ  ์žˆ์ง€๋งŒ compose + HOC๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ๊ฐˆ ๊ธธ์ด๋ฉฐ ์•„๋งˆ๋„ ์ด๋Ÿฐ ์‹์œผ๋กœ ์œ ์ง€๋  ๊ฒƒ์ž…๋‹ˆ๋‹ค... ์˜์›ํžˆ ;) MS ๋“ฑ์— ๋”ฐ๋ฅด๋ฉด ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋Š” ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ๋ฅผ ํด๋ž˜์Šค์—๋งŒ ์ฒจ๋ถ€ํ•˜๊ธฐ ์œ„ํ•œ ๊ฒƒ์ž…๋‹ˆ๋‹ค. Angular์™€ ๊ฐ™์€ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ์˜ ํฐ ์‚ฌ์šฉ์ž๋ฅผ ํ™•์ธํ•˜๋ฉด ์ด ์šฉ๋Ÿ‰์—์„œ๋งŒ ์‚ฌ์šฉ๋œ๋‹ค๋Š” ๊ฒƒ์„ ์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด TypeScript ์œ ์ง€ ๊ด€๋ฆฌ์ž๋ฅผ ์„ค๋“ํ•  ์ˆ˜ ์žˆ์„์ง€ ์˜์‹ฌ๋ฉ๋‹ˆ๋‹ค.

์ง„์ •ํ•œ ๊ธฐ๋Šฅ ๊ตฌ์„ฑ์„ ๊ฐ€๋Šฅํ•˜๊ฒŒ ํ•˜๊ณ  ๊ทธ๋Ÿฌํ•œ ์ฐธ์—ฌ๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๊ทธ๋Ÿฌํ•œ ๊ฐ•๋ ฅํ•œ ๊ธฐ๋Šฅ์ด TS ํŒ€์—์„œ ์˜ค๋žซ๋™์•ˆ ๋ฌด์‹œ๋˜์–ด ์™”๋‹ค๋Š” ๊ฒƒ์€ ์Šฌํ”„๊ณ  ์•ฝ๊ฐ„ ์ด์ƒํ•ฉ๋‹ˆ๋‹ค.

์ด๊ฒƒ์€ ์‹ค์ œ๋กœ ์šฐ๋ฆฌ๊ฐ€ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๋Š” ๋ฐฉ๋ฒ•์— ํ˜๋ช…์„ ์ผ์œผํ‚ฌ ์ˆ˜ ์žˆ๋Š” ๊ธฐ๋Šฅ์ž…๋‹ˆ๋‹ค. ๋ชจ๋“  ์‚ฌ๋žŒ์ด Bitly ๋˜๋Š” NPM๊ณผ ๊ฐ™์€ ๊ฒƒ์— ๋Œ€ํ•œ ์ž‘์€ ๋ฏน์Šค์ธ์„ ๋ฆด๋ฆฌ์Šคํ•˜๊ณ  Typescript์—์„œ ์ •๋ง ๋ฉ‹์ง„ ์ฝ”๋“œ ์žฌ์‚ฌ์šฉ์„ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋‚ด ์ž์‹ ์˜ ํ”„๋กœ์ ํŠธ์—์„œ ๋‚˜๋Š” ์ฆ‰์‹œ @Poolable @Initable @Translating ์„ ๋งŒ๋“ค๊ณ  ์•„๋งˆ๋„ ๋” ๋งŽ์ด ๋งŒ๋“ค ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๋ชจ๋“  ๊ฐ•๋ ฅํ•œ TS ์ฝ”์–ด ํŒ€์„ ๋ถ€ํƒํ•ฉ๋‹ˆ๋‹ค. ๊ตฌํ˜„์— "ํ•„์š”ํ•œ ๋ชจ๋“  ๊ฒƒ"์€ ๋ฐ˜ํ™˜๋œ ์ธํ„ฐํŽ˜์ด์Šค๊ฐ€ ์กด์ค‘๋˜์–ด์•ผ ํ•œ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

// taken from my own lib out of context
export function Initable<T extends { new(...args: any[]): {} }>(constructor: T): T & Constructor<IInitable<T>> {
    return class extends constructor implements IInitable<T> {
        public init(obj: Partial<T> | any, mapping?: any) {
            setProperties(this, obj, mapping);
            return this
        }
    }
}

์ด ์ฝ”๋“œ๋ฅผ ๋ถˆ๋งŒ ์—†์ด ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

<strong i="14">@Initable</strong>
class Person {
    public name: string = "";
    public age: number = 0;
    public superPower: string | null = null;
}
let sam = new Person();

sam.init({age: 17, name: "Sam", superPower: "badassery"});

@AllNamesRTake

๊ท€ํ•˜์˜ ์š”์ ์— ๋™์˜ํ•˜์ง€๋งŒ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋™์ผํ•œ ๊ฒƒ์„ ๋‹ฌ์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

class Animal {
    constructor(values: Object = {}) {
        Object.assign(this, values);
    }
}

๊ทธ๋Ÿฐ ๋‹ค์Œ init ํ•จ์ˆ˜๊ฐ€ ํ•„์š”ํ•˜์ง€๋„ ์•Š์Šต๋‹ˆ๋‹ค. ๋‹ค์Œ๊ณผ ๊ฐ™์ด ํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.

const animal = new Animal({name: 'Fred', age: 1});

@lansana
๋„ค, ํ•˜์ง€๋งŒ ๊ทธ๋ ‡๊ฒŒ ํ•˜๋ฉด ๋‚ด๊ฐ€ ์›ํ•˜๋Š” ๊ฒƒ์ด ํ•ญ์ƒ ์Šˆํผ ๋“€ํผ๊ฐ€ ์•„๋‹Œ ๋‚ด ์ƒ์„ฑ์ž๊ฐ€ ์˜ค์—ผ๋  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๋˜ํ•œ ํ’€๋ง ๊ฐ€๋Šฅํ•œ ๊ฐœ์ฒด ๋ฐ ๊ธฐํƒ€ ํ•ญ๋ชฉ์„ ๋งŒ๋“ค๊ธฐ ์œ„ํ•ด ์œ ์‚ฌํ•œ ๋ฏน์Šค์ธ์ด ์žˆ์Šต๋‹ˆ๋‹ค. ๊ตฌ์„ฑ์„ ํ†ตํ•ด ๊ธฐ๋Šฅ์„ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ๋Š” ๊ฐ€๋Šฅ์„ฑ๋งŒ ์žˆ์œผ๋ฉด ๋ฉ๋‹ˆ๋‹ค. init ์˜ˆ์ œ๋Š” ์ƒ์„ฑ์ž๋ฅผ ๋”๋Ÿฝํžˆ์ง€ ์•Š๊ณ  ์ˆ˜ํ–‰ํ•œ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๋Š” ๋ฐ ํ•„์š”ํ•œ ๋ฐฉ๋ฒ•์ด๋ฏ€๋กœ ๋‹ค๋ฅธ ํ”„๋ ˆ์ž„์›Œํฌ์—์„œ ์œ ์šฉํ•ฉ๋‹ˆ๋‹ค.

@AllNamesRTaken ์˜ค๋žซ๋™์•ˆ ์ด ์ƒํƒœ์— ์žˆ์—ˆ๊ณ  ์ œ์•ˆ์ด ์ด๋ฏธ 2๋‹จ๊ณ„์— ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์ง€๊ธˆ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋ฅผ ๊ฑด๋“œ๋ ค๋„ ์†Œ์šฉ์ด ์—†์Šต๋‹ˆ๋‹ค. https://github.com/tc39/proposal-decorators ๊ฐ€ ์™„๋ฃŒ๋  ๋•Œ๊นŒ์ง€ ๊ธฐ๋‹ค๋ฆฌ์„ธ์š”. ๊ทธ๋Ÿฌ๋ฉด ๋ชจ๋“  ์‚ฌ๋žŒ์ด ๋™์˜ํ•˜๋Š” ํ˜•์‹์œผ๋กœ ๊ฐ€์ ธ์˜ฌ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

@์ฟ ํ‚ค๋ชฌ์Šคํƒ€
๋‚ด๊ฐ€ ์š”์ฒญํ•˜๋Š” ๊ฒƒ์€ ์ˆœ์ „ํžˆ ๊ธฐ๋Šฅ์ด ์•„๋‹ˆ๋ผ ์œ ํ˜•์— ๊ด€ํ•œ ๊ฒƒ์ด๊ธฐ ๋•Œ๋ฌธ์— ๋‚˜๋Š” ๋‹น์‹ ์—๊ฒŒ ๊ฐ•๋ ฅํ•˜๊ฒŒ ๋™์˜ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ES ๋ฌผ๊ฑด๊ณผ ๊ด€๋ จ์ด ์žˆ๋‹ค๋ฉด ๋ณ„๋กœ ์—†์Šต๋‹ˆ๋‹ค. ์œ„์˜ ๋‚ด ์†”๋ฃจ์…˜์€ ์ด๋ฏธ ์ž‘๋™ํ•˜์ง€๋งŒ ์บ์ŠคํŠธํ•˜๊ณ  ์‹ถ์ง€ ์•Š์Šต๋‹ˆ๋‹ค..

@AllNamesRTaken ๊ฒฝ๊ณ ๊ฐ€ ์ „ํ˜€ ์—†๋Š” ๋ฏน์Šค์ธ์œผ๋กœ _์˜ค๋Š˜_ ์ด ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

function setProperties(t: any, o: any, mapping: any) {}

type Constructor<T> = { new(...args: any[]): T };

interface IInitable<T> {
  init(obj: Partial<T> | any, mapping?: any): this;
}

// taken from my own lib out of context
function Initable<T extends Constructor<{}>>(constructor: T): T & Constructor<IInitable<T>> {
    return class extends constructor implements IInitable<T> {
        public init(obj: Partial<T> | any, mapping?: any) {
            setProperties(this, obj, mapping);
            return this
        }
    }
}

class Person extends Initable(Object) {
    public name: string = "";
    public age: number = 0;
    public superPower: string | null = null;
}
let sam = new Person();
sam.init({age: 17, name: "Sam", superPower: "badassery"});

์•ž์œผ๋กœ ๋ฏน์Šค์ธ ์ œ์•ˆ์„ JS๋กœ ๊ฐ€์ ธ์˜ค๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์ด ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

mixin Initable {
  public init(obj: Partial<T> | any, mapping?: any) {
    setProperties(this, obj, mapping);
    return this
  }
}

class Person extends Object with Initable {
    public name: string = "";
    public age: number = 0;
    public superPower: string | null = null;
}
let sam = new Person();
sam.init({age: 17, name: "Sam", superPower: "badassery"});

@justinfagnani mixin์€ ๋‚ด๊ฐ€ ์ด๋Ÿฌํ•œ ๊ธฐ๋Šฅ์„ ์‹œ์ž‘ํ•˜๋Š” ๋ฐฉ๋ฒ•์ด์—ˆ๊ณ  ๋‚ด ๊ตฌํ˜„์€ ์‹ค์ œ๋กœ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค.

class Person extends Initable(Object) {
    public name: string = "";
    public age: number = 0;
    public superPower: string | null = null;
}
let sam = new Person();     
sam.init({age: 17, name: "Sam", superPower: "badassery"});

์ด๊ฒƒ์€ ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•์œผ๋กœ ๋ฉ‹์ง€์ง€๋งŒ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๊ฐ€ ๋‚ด ์˜๊ฒฌ์œผ๋กœ๋Š” ์œ ํ˜•์„ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ๋„๋ก ํ—ˆ์šฉํ•˜๋Š” ์žฅ์ ์„ ์‹ค์ œ๋กœ ์ œ๊ฑฐํ•˜์ง€๋Š” ์•Š์Šต๋‹ˆ๋‹ค.

ํŽธ์ง‘ : ๋˜ํ•œ init์— ๋Œ€ํ•œ ๋ถ€๋ถ„์—์„œ ํƒ€์ดํ•‘์„ ๋Š์Šจํ•˜๊ฒŒ ํ•ฉ๋‹ˆ๋‹ค.

์ด ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•˜๋ฉด HoC๋ฅผ ๋” ์‰ฝ๊ฒŒ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
์ด ๊ธฐ๋Šฅ์ด ์ถ”๊ฐ€๋˜๊ธฐ๋ฅผ ๋ฐ”๋ž๋‹ˆ๋‹ค

@kgtkr ๊ทธ๊ฒŒ ๋‚ด๊ฐ€ ์ด๊ฒƒ์„ ๊ฐ„์ ˆํžˆ ์›ํ•˜๋Š” ์ฃผ๋œ ์ด์œ ์ž…๋‹ˆ๋‹ค ...

react-router ์ •์˜์— ์•ฝ๊ฐ„์˜ ๋น„์ƒ์ด ์žˆ์Šต๋‹ˆ๋‹ค. ์ผ๋ถ€ ์‚ฌ๋žŒ๋“ค์€ ํด๋ž˜์Šค ๋ฐ์ฝ”๋ ˆ์ด์…˜ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ฐ–๋Š” ๊ฒƒ๋ณด๋‹ค ์œ ํ˜• ์•ˆ์ „์„ฑ์ด ๋” ์ค‘์š”ํ•˜๋‹ค๊ณ  ๊ฒฐ์ •ํ–ˆ๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ๋งจ ์•„๋ž˜ ์ด์œ ๋Š” withRouter ๊ฐ€ ์ผ๋ถ€ ์†Œํ’ˆ์„ ์„ ํƒ ์‚ฌํ•ญ์œผ๋กœ ๋งŒ๋“ค๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

์ด์ œ ์‚ฌ๋žŒ๋“ค์ด ์žฅ์‹ ๋Œ€์‹  withRouter ์˜ ๊ธฐ๋Šฅ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์‚ฌ์šฉํ•˜๋„๋ก ๊ฐ•์š”๋ฐ›๋Š” ๋ถˆํ™”๊ฐ€ ์žˆ๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

์ด ๊ธฐ๋Šฅ์„ ํ•ด๊ฒฐํ•˜๊ธฐ ์‹œ์ž‘ํ•˜๋ฉด ์„ธ์ƒ์ด ๋” ํ–‰๋ณตํ•œ ๊ณณ์ด ๋  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๊ฐ™์€ ๋ถˆํ™”*๊ฐ€ ์–ผ๋งˆ โ€‹โ€‹์ „์— material-ui ํƒ€์ดํ•‘๊ณผ withStyle ์—์„œ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค. ์ด๋Š” ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋กœ ์‚ฌ์šฉํ•˜๋„๋ก ์„ค๊ณ„๋˜์—ˆ์ง€๋งŒ TypeScript ์‚ฌ์šฉ์ž๊ฐ€ ์•ˆ์ „ํ•˜๊ฒŒ ์‚ฌ์šฉํ•˜๋ ค๋ฉด ๋‹ค์Œ์„ ์‚ฌ์šฉํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ •๊ทœ ๊ธฐ๋Šฅ์œผ๋กœ. ๋จผ์ง€๊ฐ€ ๋Œ€๋ถ€๋ถ„ ํ•ด๊ฒฐ๋˜์—ˆ์ง€๋งŒ ํ”„๋กœ์ ํŠธ๋ฅผ ์ฒ˜์Œ ์ ‘ํ•˜๋Š” ์‚ฌ๋žŒ๋“ค์—๊ฒŒ๋Š” ์ง€์†์ ์ธ ํ˜ผ๋ž€์˜ ์›์ธ์ด ๋ฉ๋‹ˆ๋‹ค!

* ๊ธ€์Ž„, "๋ถˆํ™”"๋Š” ๊ฐ•ํ•œ ๋‹จ์–ด ์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค

๋‚˜๋Š” ์ด๊ฒƒ์„ ์˜ค๋žซ๋™์•ˆ ์ง€์ผœ๋ณด์•˜๊ณ , ๊ทธ๊ฒƒ์ด ๋„์ฐฉํ•  ๋•Œ๊นŒ์ง€ ๋‹ค๋ฅธ ์‚ฌ๋žŒ๋“ค์ด ์•ž์œผ๋กœ ํ˜ธํ™˜๋˜๋Š” ๋ฐฉ์‹์œผ๋กœ ์ด ๋™์ž‘์„ ๋‹ฌ์„ฑํ•˜๊ธฐ ์œ„ํ•ด ๋‚˜์˜ ์ž‘์€ ํ•ดํ‚น์œผ๋กœ๋ถ€ํ„ฐ ์ด์ต์„ ์–ป์„ ์ˆ˜ ์žˆ๊ธฐ๋ฅผ ๋ฐ”๋ž๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ ์—ฌ๊ธฐ, ์•„์ฃผ ๊ธฐ๋ณธ์ ์ธ ์Šค์นผ๋ผ ์Šคํƒ€์ผ์˜ ์ผ€์ด์Šค ํด๋ž˜์Šค copy ๋ฉ”์†Œ๋“œ๋ฅผ ๊ตฌํ˜„ํ–ˆ์Šต๋‹ˆ๋‹ค...

๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋ฅผ ๊ตฌํ˜„ํ–ˆ์Šต๋‹ˆ๋‹ค.

type Constructor<T> = { new(...args: any[]): T };

interface CaseClass {
  copy(overrides?: Partial<this>): this
}

function CaseClass<T extends Constructor<{}>>(constructor: T): T & Constructor<CaseClass> {
  return class extends constructor implements CaseClass {
    public copy(overrides: Partial<this> = {}): this {
      return Object.assign(Object.create(Object.getPrototypeOf(this)), this, overrides);
    }
  }
}

์ด ์ฝ”๋“œ๋Š” copy ๋ฉ”์„œ๋“œ๊ฐ€ ์—ฐ๊ฒฐ๋œ ์ต๋ช… ํด๋ž˜์Šค๋ฅผ ๋งŒ๋“ญ๋‹ˆ๋‹ค. ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋ฅผ ์ง€์›ํ•˜๋Š” ํ™˜๊ฒฝ์—์„œ JavaScript์—์„œ ์˜ˆ์ƒ๋Œ€๋กœ ์ •ํ™•ํ•˜๊ฒŒ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค.

TypeScript์—์„œ ์ด๊ฒƒ์„ ์‚ฌ์šฉํ•˜๊ณ  ์‹ค์ œ๋กœ ์œ ํ˜• ์‹œ์Šคํ…œ์ด ๋Œ€์ƒ ํด๋ž˜์Šค์˜ ์ƒˆ ๋ฉ”์„œ๋“œ๋ฅผ ๋ฐ˜์˜ํ•˜๋„๋ก ํ•˜๋ ค๋ฉด ๋‹ค์Œ ํ•ดํ‚น์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

class MyCaseClass extends CaseClass(class {
  constructor(
    public fooKey: string,
    public barKey: string,
    public bazKey: string
  ) {}
}) {}

MyCaseClass CaseClass ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ ๋‚ด๋ถ€์˜ ์ต๋ช… ํด๋ž˜์Šค์—์„œ ์ƒ์†๋œ copy ๋ฉ”์„œ๋“œ์— ๋Œ€ํ•œ ์ž…๋ ฅ์„ ๋…ธ์ถœํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  TypeScript๊ฐ€ ์„ ์–ธ๋œ ์œ ํ˜•์˜ ๋ณ€ํ˜•์„ ์ง€์›ํ•˜๋ฉด ์ด ์ฝ”๋“œ๋Š” ์˜ˆ๊ธฐ์น˜ ์•Š์€ ์˜ค๋ฅ˜ ์—†์ด ์ผ๋ฐ˜์ ์ธ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ ๊ตฌ๋ฌธ <strong i="18">@CaseClass</strong> etc ์œผ๋กœ ์‰ฝ๊ฒŒ ์ˆ˜์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋‹ค์Œ ์ฃผ์š” TypeScript ๋ฆด๋ฆฌ์Šค์—์„œ ์ด๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ๋‹ค๋ฉด ์ข‹์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ํ”„๋ก์‹œ ํด๋ž˜์Šค์˜ ์ด์ƒํ•œ ์—‰๋ง์„ ๋‚ด๋ณด๋‚ด๋Š” ๋Œ€์‹  ๋” ๊นจ๋—ํ•˜๊ณ  ๊ฐ„๊ฒฐํ•œ ์ฝ”๋“œ๋ฅผ ๋งŒ๋“œ๋Š” ๋ฐ ๋„์›€์ด ๋  ๊ฒƒ์ด๋ผ๊ณ  ๋ฏฟ์Šต๋‹ˆ๋‹ค.

์ด ๊ธฐ๋Šฅ์€ ์–ธ์ œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ?

๋ฐ˜๋ณต๋˜๋Š” ์ž‘์—…์„ ์ฒ˜๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด ํด๋ž˜์Šค ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์‹ถ์—ˆ์Šต๋‹ˆ๋‹ค.
ํ•˜์ง€๋งŒ ์ด์ œ ํด๋ž˜์Šค๋ฅผ ์ดˆ๊ธฐํ™”ํ•  ๋•Œ ๋‹ค์Œ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค. Expected 0 arguments, but got 1

function Component<T extends { new(...args: any[]): {} }>(target: T) {
    return class extends target {
        public constructor(...args: any[]) {
            super(...args);
            resolveDependencies(this, args[0])
        }
    }
}

<strong i="8">@Component</strong>
export class ExampleService {
    @Inject(ExampleDao) private exampleDao: ExampleDao;

    // <strong i="9">@Component</strong> will automatically do this for me 
    // public constructor(deps: any) {
    //  resolveDependencies(this, deps);
    // }

    public getExample(id: number): Promise<Example | undefined> {
        return this.exampleDao.getOne(id);
    }
}

new ExampleService({ exampleDao }) // TS2554: Expected 0 arguments, but got 1.

์ด ๊ธฐ๋Šฅ์ด ๊ณง ์ œ๊ณต๋˜๊ธฐ๋ฅผ ๋ฐ”๋ž๋‹ˆ๋‹ค! :)

@iainreid820 ์ด ์ ‘๊ทผ ๋ฐฉ์‹์„ ์‚ฌ์šฉํ•˜๋ฉด์„œ ์ด์ƒํ•œ ๋ฒ„๊ทธ๋ฅผ ๊ฒฝํ—˜ํ•˜์…จ๋‚˜์š”?

์˜ค๋žœ ๊ธฐ๋‹ค๋ฆผ! ๊ทธ๋™์•ˆ ํ˜„์žฌ ๋กœ๋“œ๋งต์— ์žˆ๋Š” ๋ฌธ์ œ๋กœ ์ด ๋ฌธ์ œ๊ฐ€ ํ•ด๊ฒฐ๋˜๊ณ  ์žˆ์Šต๋‹ˆ๊นŒ?
๋ฌธ์ œ 5453 ๊ณผ ๊ฐ™์€?

์ €๋Š” Material UI ๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์œผ๋ฉฐ TypeScript๊ฐ€ withStyles ์— ๋Œ€ํ•œ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ ๊ตฌ๋ฌธ์„ ์ง€์›ํ•˜์ง€ ์•Š๋Š”๋‹ค๋Š” ๊ฒƒ์„ ๊นจ๋‹ฌ์•˜์Šต๋‹ˆ๋‹ค. https://material-ui.com/guides/typescript/#decorating -components

๋‹ค์Œ TypeScript ๋ฆด๋ฆฌ์Šค์—์„œ ํ•ด๋‹น ์ œํ•œ์„ ์ˆ˜์ •ํ•˜์‹ญ์‹œ์˜ค. ํด๋ž˜์Šค ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋Š” ์ง€๊ธˆ ๋‚˜์—๊ฒŒ ๊ฝค ์“ธ๋ชจ์—†๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

Morphism Js ์˜ ๋ฉ”์ธํ…Œ์ด๋„ˆ๋กœ์„œ ์ด๊ฒƒ์€ ์ด๋Ÿฌํ•œ ์ข…๋ฅ˜์˜ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์— ๋Œ€ํ•œ ํฐ ํ•œ๊ณ„์ž…๋‹ˆ๋‹ค. ๋‚˜๋Š” ํ•จ์ˆ˜ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ์˜ ์†Œ๋น„์ž๊ฐ€ ํ•จ์ˆ˜ https://github.com/nobrainr/morphism# --toclassobject-decorator์˜ ๋Œ€์ƒ ์œ ํ˜•์„ ์ง€์ •ํ•ด์•ผ ํ•˜๋Š” ๊ฒƒ์„ ํ”ผํ•˜๊ณ  ์‹ถ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด HOF ๋Œ€์‹  ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์•ฝ๊ฐ„ ์“ธ๋ชจ์—†๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ๋“ค๋ฆฝ๋‹ˆ๋‹ค. ๐Ÿ˜•
์ด์— ๋Œ€์ฒ˜ํ•  ๊ณ„ํš์ด ์žˆ์Šต๋‹ˆ๊นŒ? ์ด ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ•˜๋Š” ๋ฐ ๋„์›€์ด ๋˜๋Š” ๋ฐฉ๋ฒ•์ด ์žˆ์Šต๋‹ˆ๊นŒ? ๋ฏธ๋ฆฌ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค!

@bikeshedder ๋จธํ‹ฐ๋ฆฌ์–ผ UI ์˜ˆ์ œ๋Š” ํด๋ž˜์Šค ๋ฏน์Šค์ธ ์‚ฌ์šฉ ์‚ฌ๋ก€์ด๋ฉฐ ๋ฏน์Šค์ธ์—์„œ ์˜ฌ๋ฐ”๋ฅธ ์œ ํ˜•์„ ์–ป์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋Œ€์‹ ์—:

const DecoratedClass = withStyles(styles)(
  class extends React.Component<Props> {
...
}

์“ฐ๋‹ค:

class DecoratedClass extends withStyles(styles)(React.Component<Props>) {
...
}

@justinfagnani ๊ทธ๊ฒƒ์€ ๋‚˜๋ฅผ ์œ„ํ•ด ์ž‘๋™ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค :

ss 2018-10-16 at 10 00 47

๋‚ด ์ฝ”๋“œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค. https://gist.github.com/G-Rath/654dff328dbc3ae90d16caa27a4d7262

@G-Rath ๋Œ€์‹  new () => React.Component<Props, State> ๊ฐ€ ์ž‘๋™ํ•ด์•ผ ํ•œ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๊นŒ?

@emyann ์ฃผ์‚ฌ์œ„๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. ์ƒˆ ์ฝ”๋“œ๋กœ ์š”์ง€๋ฅผ ์—…๋ฐ์ดํŠธํ–ˆ์ง€๋งŒ ์ด๊ฒƒ์ด ์˜๋ฏธํ•˜๋Š” ๋ฐ”์ž…๋‹ˆ๊นŒ?

class CardSection extends withStyles(styles)(new () => React.Component<Props, State>) {

ํ˜•์‹์„ ์ง€์ •ํ•ด๋„ extends withStyles(styles)(...) ๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ ์ ์ ˆํ•œ ์ œ์•ˆ์ฒ˜๋Ÿผ ๋“ค๋ฆฌ์ง€ ์•Š์Šต๋‹ˆ๋‹ค. withStyles๋Š” ํด๋ž˜์Šค ๋ฏน์Šค์ธ์ด ์•„๋‹™๋‹ˆ๋‹ค.

withStyles๋Š” A ๊ตฌ์„ฑ ์š”์†Œ ํด๋ž˜์Šค๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ $ B ํด๋ž˜์Šค๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค. ์ด ํด๋ž˜์Šค๋Š” ๋ Œ๋”๋ง๋  ๋•Œ A ํด๋ž˜์Šค๋ฅผ ๋ Œ๋”๋งํ•˜๊ณ  ์—ฌ๊ธฐ์— ์†Œํ’ˆ + classes ์†Œํ’ˆ์„ ์ „๋‹ฌํ•ฉ๋‹ˆ๋‹ค.

withStyles์˜ ๋ฐ˜ํ™˜ ๊ฐ’์„ ํ™•์žฅํ•˜๋ฉด ์‹ค์ œ๋กœ classes ์†Œํ’ˆ์„ ๋ฐ›๋Š” A ํด๋ž˜์Šค๋ฅผ ๊ตฌํ˜„ํ•˜๋Š” ๋Œ€์‹  B ๋ž˜ํผ๋ฅผ ํ™•์žฅํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

ํ˜•์‹์— ๊ด€๊ณ„์—†์ด extends withStyles(styles)(...) ๊ธฐ๋ณธ์ ์œผ๋กœ ์ ์ ˆํ•œ ์ œ์•ˆ์ฒ˜๋Ÿผ ๋“ค๋ฆฌ์ง€ ์•Š์Šต๋‹ˆ๋‹ค. withStyles๋Š” ํด๋ž˜์Šค ๋ฏน์Šค์ธ์ด ์•„๋‹™๋‹ˆ๋‹ค.

๋ฌผ๋ก . ์™œ ์—ฌ๊ธฐ์— ๋งŽ์€ ๋ฐ˜๋ฐœ์ด ์žˆ๋Š”์ง€ ์ž˜ ๋ชจ๋ฅด๊ฒ ์Šต๋‹ˆ๋‹ค.

์ฆ‰, ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋Š” 3๋‹จ๊ณ„์— ๋งค์šฐ ๊ฐ€๊น๊ธฐ ๋•Œ๋ฌธ์— TS๊ฐ€ ๊ณง ์ ์ ˆํ•œ ์ง€์›์„ ๋ฐ›์„ ๊ฒƒ์ด๋ผ๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

๋‚˜๋Š” ๋” ๊นจ๋—ํ•œ ๊ตฌ๋ฌธ์„ ์›ํ•˜๋Š” ์‚ฌ๋žŒ๋“ค์˜ ๋ง์„ ๋“ฃ์Šต๋‹ˆ๋‹ค. ์—ฌ๋Ÿฌ HoC๋ฅผ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋กœ ์ ์šฉํ•  ๋•Œ. ์šฐ๋ฆฌ๊ฐ€ ์‚ฌ์šฉํ•˜๋Š” ์ž„์‹œ ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•์€ ์‹ค์ œ๋กœ ํŒŒ์ดํ”„ ํ•จ์ˆ˜ ๋‚ด๋ถ€์— ์—ฌ๋Ÿฌ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋ฅผ ๋ž˜ํ•‘ํ•œ ๋‹ค์Œ ํ•ด๋‹น ์ˆœ์ˆ˜ ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๊ตฌ์„ฑ ์š”์†Œ๋ฅผ ์žฅ์‹ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์˜ˆ

@flow([
  withStyles(styles),
  connect(mapStateToProps),
  decorateEverything(),
])
export class HelloWorld extends Component<Props, State> {
  ...
}

์—ฌ๊ธฐ์„œ flow ๋Š” lodash.flow ์ž…๋‹ˆ๋‹ค. ๋งŽ์€ ์œ ํ‹ธ๋ฆฌํ‹ฐ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๊ฐ€ recompose , Rx.pipe ๋“ฑ๊ณผ ๊ฐ™์€ ๊ฒƒ์„ ์ œ๊ณตํ•˜์ง€๋งŒ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์„ค์น˜ํ•˜์ง€ ์•Š์œผ๋ ค๋ฉด ๋ฌผ๋ก  ๊ฐ„๋‹จํ•œ ํŒŒ์ดํ”„ ํ•จ์ˆ˜๋ฅผ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” ๊ฒƒ๋ณด๋‹ค ์ฝ๊ธฐ๊ฐ€ ๋” ์‰ฝ์Šต๋‹ˆ๋‹ค.

export const decoratedHelloWorld = withStyles(styles)(
  connect(mapStateToProps)(
    decorateEverything(
       HelloWorld
))))

๋‚ด๊ฐ€ ์ด๊ฒƒ์„ ์‚ฌ์šฉํ•˜๋Š” ๋˜ ๋‹ค๋ฅธ ์ด์œ ๋Š” ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ ์‚ฌ์–‘์ด ๋ฐœํ‘œ๋˜๊ณ  ์ ์ ˆํ•˜๊ฒŒ ์ง€์›๋˜๋ฉด ์ด ํŒจํ„ด์„ ์‰ฝ๊ฒŒ ์ฐพ๊ณ  ๊ต์ฒดํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

@justinfagnani ์ด์ƒํ•˜๊ฒŒ extends React.Component<Props, State> ๋ฅผ extends withStyles(styles)(React.Component<Props, State>) ๋กœ ๋ณ€๊ฒฝํ•˜๋ ค๊ณ  ํ•˜๋ฉด ESLint์—์„œ ๊ตฌ๋ฌธ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•˜๋ฏ€๋กœ ๋™์ผํ•œ ๋ฐฉ์‹์œผ๋กœ @G-Rath์˜ ์œ ํ˜• ์˜ค๋ฅ˜๋ฅผ ํ™•์ธํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

ํ•˜์ง€๋งŒ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ํ•˜๋ฉด new ๋ฌธ์ œ(๊ฐ™์€ ๋ฌธ์ œ์ผ ์ˆ˜๋„?)๊ฐ€ ๋‚˜ํƒ€๋‚ฉ๋‹ˆ๋‹ค.

class MyComponent extends React.Component<Props, State> {
  /* ... */
}

const _MyComponent = withStyles(styles)(MyComponent)
const test = new _MyComponent // <--------- ERROR

์˜ค๋ฅ˜๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

Cannot use 'new' with an expression whose type lacks a call or construct signature.

์ด๊ฒƒ์€ Material UI์—์„œ ๋ฐ˜ํ™˜๋œ ์œ ํ˜•์ด ์ƒ์„ฑ์ž๊ฐ€ ์•„๋‹˜์„ ์˜๋ฏธํ•ฉ๋‹ˆ๊นŒ(๊ทธ๋ž˜์•ผ ํ•˜์ง€๋งŒ)?

@sagar-sm ํ•˜์ง€๋งŒ Material UI ์œ ํ˜•์œผ๋กœ ๋ณด๊ฐ•๋œ ์˜ฌ๋ฐ”๋ฅธ ์œ ํ˜•์„ ์–ป์—ˆ์Šต๋‹ˆ๊นŒ? ๋‹น์‹ ์ด ํ•  ๊ฒƒ ๊ฐ™์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์ฐธ๊ณ ๋กœ ์ €๋Š” Material UI์˜ withStyles ๋ฅผ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋กœ ์‚ฌ์šฉํ•˜๋ ค๊ณ  ํ–ˆ๊ธฐ ๋•Œ๋ฌธ์— ์ด๊ฒƒ์„ ์šฐ์—ฐํžˆ ๋ฐœ๊ฒฌํ–ˆ๋Š”๋ฐ ์ž‘๋™ํ•˜์ง€ ์•Š์•„ ๋‹ค์Œ ์งˆ๋ฌธ์„ ํ–ˆ์Šต๋‹ˆ๋‹ค. https://stackoverflow.com/questions/53138167

์ด๊ฒƒ์ด ํ•„์š”ํ•˜๋ฉด ๋น„๋™๊ธฐ ํ•จ์ˆ˜๋ฅผ bluebird๋กœ ๋ฐ˜ํ™˜ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋น„์Šทํ•œ ์ผ์„ ํ•˜๋ ค๊ณ  ํ–ˆ์Šต๋‹ˆ๋‹ค. ATM ๋‹ค์Œ ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•์„ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

๋จผ์ € ๋‚ด "mixin" ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

export type Ctor<T = {}> = new(...args: any[]) => T 
function mixinDecoratorFactory<MixinInterface>() {
    return function(toBeMixed: MixinInterface) {
        return function<MixinBase extends Ctor>(MixinBase: MixinBase) {
            Object.assign(MixinBase.prototype, toBeMixed)
            return class extends MixinBase {} as MixinBase & Ctor<MixinInterface>
        }
    }
}

์ธํ„ฐํŽ˜์ด์Šค์—์„œ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ ๋งŒ๋“ค๊ธฐ

export interface ComponentInterface = {
    selector: string,
    html: string
}
export const Component = mixinDecoratorFactory<ComponentInterface>();

๊ทธ๋ฆฌ๊ณ  ๊ทธ๊ฒƒ์ด ๋‚ด๊ฐ€ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์ž…๋‹ˆ๋‹ค.

@Component({
    html: "<div> Some Text </div>",
    selector: "app-test"
})
export class Test extends HTMLElement {
    test = "test test"
    constructor() {
        super()
        console.log("inner;     test:", this.test)
        console.log("inner;     html:", this.html)
        console.log("inner; selector:", this.selector)
    }
}

export interface Test extends HTMLElement, ComponentInterface {}
window.customElements.define(Test.prototype.selector, Test)


const test = new Test();
console.log("outer;     test:", test.test)
console.log("outer;     html:", test.html)
console.log("outer; selector:", test.selector)

ํŠธ๋ฆญ์€ ๋ณ‘ํ•ฉ ์„ ์–ธ์„ ๋งŒ๋“ค๊ธฐ ์œ„ํ•ด ํด๋ž˜์Šค์™€ ๋™์ผํ•œ ์ด๋ฆ„์œผ๋กœ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๋งŒ๋“œ๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.
์—ฌ์ „ํžˆ ํด๋ž˜์Šค๋Š” Test ์œ ํ˜•์œผ๋กœ๋งŒ ํ‘œ์‹œ๋˜์ง€๋งŒ typescript์˜ ๊ฒ€์‚ฌ๋Š” ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค.
@ -Notation ์—†์ด ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ ๋‹จ์ˆœํžˆ ํ•จ์ˆ˜๋กœ ํ˜ธ์ถœํ•˜๋ฉด ์˜ฌ๋ฐ”๋ฅธ ๊ต์ฐจ ์œ ํ˜•์„ ์–ป์„ ์ˆ˜ ์žˆ์ง€๋งŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๊ธฐ ๋•Œ๋ฌธ์— ํด๋ž˜์Šค ์ž์ฒด ๋‚ด๋ถ€์—์„œ ์œ ํ˜• ๊ฒ€์‚ฌ ๊ธฐ๋Šฅ์„ ์žƒ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ์ธํ„ฐํŽ˜์ด์Šค ์†์ž„์ˆ˜๊ฐ€ ๋” ์ด์ƒ ์—†๊ณ  ๋” ๋ณด๊ธฐ ํ‰ํ•ด ๋ณด์ž…๋‹ˆ๋‹ค. ์˜ˆ:

let Test2Comp = Component({
    html: "<div> Some Text 2 </div>",
    selector: "app-test2"
}) (
class Test2 extends HTMLElement {
    test = "test test"
    constructor() {
        super()
        console.log("inner;     test:", this.test)
        console.log("inner;     html:", this.html)     // no
        console.log("inner; selector:", this.selector) // no
    }
})

interface Test2 extends HTMLElement, ComponentInterface {} //no
window.customElements.define(Test2Comp.prototype.selector, Test2Comp)

const test2 = new Test2Comp();
console.log("outer;     test:", test2.test)
console.log("outer;     html:", test2.html)
console.log("outer; selector:", test2.selector)

์ด๋Ÿฌํ•œ ์ ‘๊ทผ ๋ฐฉ์‹์— ๋Œ€ํ•ด ์–ด๋–ป๊ฒŒ ๋งํ•ฉ๋‹ˆ๊นŒ? ์•„๋ฆ„๋‹ต์ง€๋Š” ์•Š์ง€๋งŒ ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•์œผ๋กœ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค.

์ด ๋ฌธ์ œ์— ์ง„์ „์ด ์žˆ์Šต๋‹ˆ๊นŒ? ์ด๊ฒƒ์€ ๋งค์šฐ ๋‹ค์–‘ํ•œ ๊ฐ€๋Šฅ์„ฑ์„ ์—ด์–ด์ฃผ๋Š” ๋งค์šฐ ๊ฐ•๋ ฅํ•œ ๊ธฐ๋Šฅ์ฒ˜๋Ÿผ ๋ณด์ž…๋‹ˆ๋‹ค. ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๊ฐ€ ์•„์ง ์‹คํ—˜ ๋‹จ๊ณ„์ด๊ธฐ ๋•Œ๋ฌธ์— ์ด ๋ฌธ์ œ๋Š” ํ˜„์žฌ ๋Œ€๋ถ€๋ถ„ ๋ถ€์‹คํ•˜๋‹ค๊ณ  ๊ฐ€์ •ํ•ฉ๋‹ˆ๋‹ค.

@andy-ms @ahejlsberg @sandersn์— ๋Œ€ํ•œ ๊ณต์‹ ์„ฑ๋ช…์„ ๋‚ธ๋‹ค๋ฉด ์ •๋ง ์ข‹์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๐Ÿ™

๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๊ฐ€ ์™„๋ฃŒ๋  ๋•Œ๊นŒ์ง€ ์—ฌ๊ธฐ์„œ ์•„๋ฌด ๊ฒƒ๋„ ํ•˜์ง€ ์•Š์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

@DanielRosenwasser - ์—ฌ๊ธฐ์„œ "์™„๋ฃŒ"๋ž€ ๋ฌด์—‡์„ ์˜๋ฏธํ•ฉ๋‹ˆ๊นŒ? TC39์˜ 3๋‹จ๊ณ„์— ํ•ด๋‹นํ•ฉ๋‹ˆ๊นŒ?

๊ทธ๋“ค์ด ๊ทธ๋ ‡๊ฒŒ ๋ฉ€๋ฆฌ ๊ฐˆ ์ค„ ๋ชฐ๋ž์–ด์š”! ๊ทธ๋“ค์€ ์–ธ์ œ 3๋‹จ๊ณ„์— ์ด๋ฅด๋ €์Šต๋‹ˆ๊นŒ? ์ตœ๊ทผ์ธ๊ฐ€์š”?

๊ทธ๋“ค์€ ์•„์ง ํ•˜์ง€ ์•Š์•˜๋‹ค; ๋‚˜๋Š” ๊ทธ๋“ค์ด 1์›” TC39 ํšŒ์˜์—์„œ ๋‹ค์‹œ 2๋‹จ๊ณ„์—์„œ 3๋‹จ๊ณ„๋กœ ๋ฐœ์ „ํ•  ๊ฒƒ์ด๋ผ๊ณ  ๋ฏฟ์Šต๋‹ˆ๋‹ค.

์˜์ œ ์— ๋Œ€ํ•œ ์ž์„ธํ•œ ๋‚ด์šฉ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋งž์Šต๋‹ˆ๋‹ค(1์›”์— ์ง„๊ธ‰ํ•  ์˜ˆ์ •์ธ์ง€ ํ™•์ธํ•  ์ˆ˜๋Š” ์—†์ง€๋งŒ). ๋‚˜๋Š” ๋‹จ์ง€ ๊ทธ๋“ค์ด ๊ฑฐ๊ธฐ์— ๋„์ฐฉ ํ–ˆ์„ ๋•Œ 3๋‹จ๊ณ„๊ฐ€ ์ž๊ฒฉ์ด ๋˜๋Š”์ง€ ๋ฌป๊ณ  ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.

๋‚ด ์ƒ๊ฐ์— ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ ์ œ์•ˆ์€ ์—ฌ์ „ํžˆ โ€‹โ€‹์‹ฌ๊ฐํ•œ ๋ฌธ์ œ๊ฐ€ ๋งŽ์•„์„œ 1์›”์— 3๋‹จ๊ณ„๋กœ ๋„˜์–ด๊ฐ€๋ฉด ๋ฌธ์ œ๊ฐ€ ๋˜๋Š” ํด๋ž˜์Šค ํ•„๋“œ ์ œ์•ˆ๊ณผ globalThis ์ œ์•ˆ์ฒ˜๋Ÿผ ๋‹ค์‹œ ์‹ค์ˆ˜๋ฅผ ํ•˜๊ฒŒ ๋  ๊ฒƒ์ด๋‹ค.

@hax ์ž์„ธํžˆ ์„ค๋ช…ํ•ด ์ฃผ์‹œ๊ฒ ์Šต๋‹ˆ๊นŒ?
๋‚˜๋Š” ์ด๊ฒƒ์„ ์ •๋ง๋กœ ์›ํ•˜๊ณ  ์Šฌํ”„๊ฒŒ๋„ ๋ฌธ์ œ์— ๋Œ€ํ•œ ์˜์‚ฌ ์†Œํ†ต์˜ ๋ถ€์กฑ์„ ๋ฐœ๊ฒฌํ•˜๊ณ  ๋ถˆํ–‰ํžˆ๋„ ๋ฌธ์ œ์— ๋Œ€ํ•ด ๋“ฃ์ง€ ๋ชปํ–ˆ์Šต๋‹ˆ๋‹ค.

@AllNamesRTaken ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ ์ œ์•ˆ ๋ฌธ์ œ ๋ชฉ๋ก์„ ํ™•์ธํ•˜์„ธ์š”. ๐Ÿ˜† ์˜ˆ๋ฅผ ๋“ค์–ด export before/after ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ ์ธ์ˆ˜๋Š” 3๋‹จ๊ณ„ ์ฐจ๋‹จ์ž…๋‹ˆ๋‹ค.

API ์žฌ์„ค๊ณ„์™€ ๊ฐ™์€ ๋ช‡ ๊ฐ€์ง€ ์ œ์•ˆ๋œ ๋ณ€๊ฒฝ ์‚ฌํ•ญ๋„ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋Š” ์ œ์•ˆ์ด 3๋‹จ๊ณ„์—์„œ ์•ˆ์ •์ ์ด์ง€ ์•Š๋‹ค๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•œ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

๊ทธ๋ฆฌ๊ณ  ๋ฌธ์ œ๊ฐ€ ๋˜๋Š” ํด๋ž˜์Šค ํ•„๋“œ ์ œ์•ˆ๊ณผ๋„ ๊ด€๋ จ์ด ์žˆ์Šต๋‹ˆ๋‹ค. ํด๋ž˜์Šค ํ•„๋“œ๊ฐ€ 3๋‹จ๊ณ„์— ์ด๋ฅด๋ €์ง€๋งŒ ๋ฌธ์ œ๊ฐ€ ๋„ˆ๋ฌด ๋งŽ์Šต๋‹ˆ๋‹ค. ๋‚ด๊ฐ€ ๊ฑฑ์ •ํ•˜๋Š” ํฐ ๋ฌธ์ œ๋Š” ๋งŽ์€ ๋ฌธ์ œ๋ฅผ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ(์˜ˆ: protected )์—๊ฒŒ ๋งก๊ธฐ๊ณ  ๋‘ ์ œ์•ˆ ๋ชจ๋‘์— ์ข‹์ง€ ์•Š๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์ฐธ๊ณ ๋กœ ์ €๋Š” TC39 ๋Œ€๋ฆฌ์ธ์ด ์•„๋‹ˆ๋ฉฐ ์ผ๋ถ€ TC39 ๋Œ€๋ฆฌ์ธ์€ ๋งŽ์€ ๋ฌธ์ œ์˜ ํ˜„์žฌ ์ƒํƒœ์— ๋Œ€ํ•œ ๋‚ด ์˜๊ฒฌ์— ๊ฒฐ์ฝ” ๋™์˜ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. (ํŠนํžˆ ๋‚˜๋Š” ํ˜„์žฌ TC39 ํ”„๋กœ์„ธ์Šค๊ฐ€ ๋งŽ์€ ๋…ผ๋ž€์˜ ์—ฌ์ง€๊ฐ€ ์žˆ๋Š” ๋ฌธ์ œ์—์„œ ํฐ ์‹คํŒจ๋ฅผ ๊ฒช๊ณ  ์žˆ๋‹ค๋Š” ๊ฐ•ํ•œ ์˜๊ฒฌ์„ ๊ฐ€์ง€๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ์ผ๋ถ€ ๋ฌธ์ œ๋ฅผ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ์—๊ฒŒ ์—ฐ๊ธฐํ•˜๋Š” ๊ฒƒ์€ ๋ฌธ์ œ๋ฅผ ์‹ค์ œ๋กœ ํ•ด๊ฒฐํ•˜์ง€ ๋ชปํ•˜๊ณ  ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ ์ œ์•ˆ์„ ๋” ์ทจ์•ฝํ•˜๊ฒŒ ๋งŒ๋“ญ๋‹ˆ๋‹ค.)

๋‚˜๋Š” ๊ทธ๋Ÿฐ ๊ฒƒ๋“ค์ด ํŒŒ์•…๋˜๊ณ  ์ œ์•ˆ์ด ๊ดœ์ฐฎ์„ ๊ฒƒ์ด๋ผ๊ณ  ์ƒ๊ฐํ•˜์ง€๋งŒ, ์—ฌ๊ธฐ์„œ ์ œ์•ˆ์˜ ์ƒํƒœ์— ๋Œ€ํ•ด ๋…ผ์˜ํ•˜์ง€ ์•Š๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค.

์ถฉ๋ถ„ํ•œ ํ™•์‹ ์ด ์žˆ๋Š” 3๋‹จ๊ณ„ ๋˜๋Š” 4๋‹จ๊ณ„๊ฐ€ ์•„๋งˆ๋„ ์ƒˆ๋กœ์šด ์ œ์•ˆ์„ ๊ตฌํ˜„ํ•˜๊ณ  ์ด ๋ฌธ์ œ๋ฅผ ์‚ดํŽด๋ณผ ์ˆ˜ ์žˆ๋Š” ๋‹จ๊ณ„๋ผ๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค ๋‹ค๋‹ˆ์—˜! 3๋‹จ๊ณ„๋Š” ์ผ๋ฐ˜์ ์œผ๋กœ 4์— ๋Œ€ํ•œ ๊ฐ•ํ•œ ํ™•์‹ ์„ ์˜๋ฏธํ•˜๋ฏ€๋กœ 1์›” ํšŒ์˜์— ๋Œ€ํ•ด ์†๊ฐ€๋ฝ์ด ๊ต์ฐจํ–ˆ์Šต๋‹ˆ๋‹ค.

๊ทธ๋ฆฌ๊ณ  ์—ฌ๊ธฐ์—์„œ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ ํ† ๋ก ์„ ์‹œ์ž‘ํ•ด์ฃผ์…”์„œ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค. ์ด ๊ธฐ๋Šฅ์œผ๋กœ ์ธํ•ด ๋ถ„๋…ธ์™€ ์ž์ „๊ฑฐ ๋ฐœ์‚ฐ์˜ ์ˆ˜์ค€์ด ๊ธฐ๊ดดํ•ฉ๋‹ˆ๋‹ค. ๋‚˜๋Š” ๊ทธ๋Ÿฐ ๊ฒƒ์„ ๋ณธ ์ ์ด ์—†๋‹ค ๐Ÿ˜‚

๊ธฐ๋ก์„ ์œ„ํ•ด ๊ฐ™์€ ๊ฒƒ์— ๋Œ€ํ•œ ๊ธฐ๋Šฅ ์š”์ฒญ์ด ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค: https://github.com/Microsoft/TypeScript/issues/8545

์งœ์ฆ๋‚˜๊ฒŒ ์ถฉ๋ถ„ํžˆ TypeScript๋Š” JavaScript์—์„œ ์ปดํŒŒ์ผํ•  ๋•Œ ์ด ๊ธฐ๋Šฅ์„ ์–ด๋Š ์ •๋„ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค(https://github.com/Microsoft/TypeScript/wiki/What%27s-new-in-TypeScript#better-handling-for-namespace-patterns-in -js ํŒŒ์ผ):

// javascript via typescript
var obj = {};
obj.value = 1;
console.log(obj.value);

TypeScript ์ฝ”๋“œ ์ž์ฒด์˜ ๊ฒฝ์šฐ์—๋„ ํ•จ์ˆ˜(!)(https://github.com/Microsoft/TypeScript/wiki/What%27s-new-in-TypeScript#properties-declarations-on-functions)์— ๊ด€ํ•ด์„œ ๋งŒ :

function readImage(path: string, callback: (err: any, image: Image) => void) {
    // ...
}

readImage.sync = (path: string) => {
    const contents = fs.readFileSync(path);
    return decodeImageSync(contents);
}

@DanielRosenwasser @arackaf 3๋‹จ๊ณ„๋กœ ๋„˜์–ด๊ฐ€๋Š” ์ œ์•ˆ์— ๋Œ€ํ•ด ๋ง์”€ํ•ด ์ฃผ์‹œ๊ฒ ์Šต๋‹ˆ๊นŒ? ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ ํด๋ž˜์Šค์— ํ”„๋กœํ† ํƒ€์ž… ๊ธฐ๋Šฅ์„ ์ถ”๊ฐ€ํ•˜๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ๊ตฌ์ถ•ํ•˜๋ ค๊ณ  ํ•ฉ๋‹ˆ๋‹ค.

๊ทธ๋“ค์€ ์ตœ์‹  TC39 ํšŒ์˜์—์„œ ์ง„์ฒ™๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค. ๊ทธ๋“ค์€ ๋‹ค์Œ ํšŒ์˜์—์„œ ๋‹ค์‹œ ์Šน์ง„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๊ทธ๊ฒƒ์€ ๋ถˆ๋ถ„๋ช…ํ•ฉ๋‹ˆ๋‹ค. ์ด ์‹œ์ ์—์„œ ์ œ์•ˆ์— ๋Œ€ํ•ด ๋งŽ์€ ์ด์•ผ๊ธฐ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

์—ฌ๊ธฐ ๊ด€์‹ฌ ์žˆ๋Š” ์‚ฌ๋žŒ๋“ค ์€ ์ œ์•ˆ ์ž์ฒด๋ฅผ ์ถ”์ ํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋ฉด ์Šค๋ ˆ๋“œ๋ฅผ ๋ณด๊ณ  ์žˆ๋Š” ์‚ฌ๋žŒ๋“ค๊ณผ TS ์œ ์ง€ ๊ด€๋ฆฌ์ž๋ฅผ ์œ„ํ•ด ์†Œ์Œ์„ ์ค„์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ด๊ฒƒ์— ๋Œ€ํ•œ ์—…๋ฐ์ดํŠธ๊ฐ€ ์žˆ์Šต๋‹ˆ๊นŒ?

ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•(๊ฐ๋„ :)

import { Type } from '@angular/core';

export function ExtendsWithFakes<F1>(): Type<F1>;
export function ExtendsWithFakes<F1, F2>(): Type<F1 & F2>;
export function ExtendsWithFakes<F1, F2, F3>(): Type<F1 & F2 & F3>;
export function ExtendsWithFakes<F1, F2, F3, F4>(): Type<F1 & F2 & F3 & F4>;
export function ExtendsWithFakes<F1, F2, F3, F4, F5>(): Type<F1 & F2 & F3 & F4 & F5>;
export function ExtendsWithFakes<RealT, F1>(realTypeForExtend?: Type<RealT>): Type<RealT & F1>;
export function ExtendsWithFakes<RealT, F1, F2>(realTypeForExtend?: Type<RealT>): Type<RealT & F1 & F2>;
export function ExtendsWithFakes<RealT, F1, F2, F3>(realTypeForExtend?: Type<RealT>): Type<RealT & F1 & F2 & F3>;
export function ExtendsWithFakes<RealT, F1, F2, F3, F4>(
    realTypeForExtend?: Type<RealT>
): Type<RealT & F1 & F2 & F3 & F4>;
export function ExtendsWithFakes<RealT, F1, F2, F3, F4, F5>(
    realTypeForExtend?: Type<RealT>
): Type<RealT & F1 & F2 & F3 & F4 & F5> {
    if (realTypeForExtend) {
        return realTypeForExtend as Type<any>;
    } else {
        return class {} as Type<any>;
    }
}

interface IFake {
    fake(): string;
}

function UseFake() {
    return (target: Type<any>) => {
        target.prototype.fake = () => 'hello fake';
    };
}

class A {
    a() {}
}

class B {
    b() {}
}

@UseFake()
class C extends ExtendsWithFakes<A, IFake, B>(A) {
    c() {
        this.fake();
        this.a();
        this.b(); // failed at runtime
    }
}

์ด "๊ทธ๋™์•ˆ" ์‰ฌ์šด ์†”๋ฃจ์…˜์— ๋Œ€ํ•ด ์–ด๋–ป๊ฒŒ ์ƒ๊ฐํ•˜์‹ญ๋‹ˆ๊นŒ?
https://stackoverflow.com/a/55520697/1053872

Mobx-state-tree๋Š” cast() ํ•จ์ˆ˜์™€ ์œ ์‚ฌํ•œ ์ ‘๊ทผ ๋ฐฉ์‹์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ๊ธฐ๋ถ„์ด ์ข‹์ง€๋Š” ์•Š์ง€๋งŒ... ๋„ˆ๋ฌด ๊ท€์ฐฎ๊ฒŒ ํ•˜์ง€๋„ ์•Š์Šต๋‹ˆ๋‹ค. ๋” ์ข‹์€ ๊ฒƒ์ด ๋‚˜์˜ฌ ๋•Œ๋งˆ๋‹ค ๊บผ๋‚ด๊ธฐ๊ฐ€ ์‰ฝ์Šต๋‹ˆ๋‹ค.

๋‚˜๋Š” ์ด๊ฒƒ์˜ ๋ผ์ธ์— ๋”ฐ๋ผ ๋ฌด์–ธ๊ฐ€๋ฅผ ํ•  ์ˆ˜ ์žˆ๊ธฐ๋ฅผ ์›ํ•ฉ๋‹ˆ๋‹ค โค๏ธ
์ด๊ฒƒ์ด ๋ฐ”๋กœ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๊ฐ€ ๊ฐ€์ ธ์•ผ ํ•  ํž˜์ด ์•„๋‹๊นŒ์š”?

class B<C = any> {}

function ChangeType<T>(to : T) : (from : any) => T;
function InsertType<T>(from : T) : B<T>;

@ChangeType(B)
class A {}

// A === B

// or

<strong i="7">@InsertType</strong>
class G {}

// G === B<G>

const g = new G(); // g : B<G>

A === B // equals true

const a : B = new A();  // valid
const b = new B();

typeof a === typeof b // valid

๋ฐ์ฝ”๋ ˆ์ดํŒ…๋œ ํด๋ž˜์Šค ์†์„ฑ์„ ์ž…๋ ฅํ•˜๋Š” ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•์„ ๋งŒ๋“œ๋Š” ๋ฐ ์ƒ๋‹นํ•œ ์‹œ๊ฐ„์„ ํ• ์• ํ–ˆ์Šต๋‹ˆ๋‹ค. ์ด ์Šค๋ ˆ๋“œ์˜ ์‹œ๋‚˜๋ฆฌ์˜ค์— ๋Œ€ํ•œ ์‹คํ–‰ ๊ฐ€๋Šฅํ•œ ์†”๋ฃจ์…˜์ด ๋  ๊ฒƒ์ด๋ผ๊ณ  ์ƒ๊ฐํ•˜์ง€ ์•Š์ง€๋งŒ ์ผ๋ถ€ ๋ถ€๋ถ„์€ ์œ ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ด€์‹ฌ ์žˆ์œผ์‹  ๋ถ„๋“ค์€ ๋ฏธ๋””์—„์—์„œ ์ œ ๊ธ€์„ ํ™•์ธํ•ด์ฃผ์„ธ์š”.

์ด ๋ฌธ์ œ์— ๋Œ€ํ•œ ์—…๋ฐ์ดํŠธ๊ฐ€ ์žˆ์Šต๋‹ˆ๊นŒ?

์ด๊ฑธ๋กœ ์–ด๋–ป๊ฒŒ ํ•ด์š”?

์ด ๋ฌธ์ œ์˜ ๊ฒฐ๊ณผ๋Š” ๋ฌด์—‡์ด๋ฉฐ ํ˜„์žฌ ์–ด๋–ป๊ฒŒ ์ž‘๋™ํ•ฉ๋‹ˆ๊นŒ?

mixin-class๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํ•ด๋‹น ํšจ๊ณผ๋ฅผ ์–ป์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
https://mariusschulz.com/blog/mixin-classes-in-typescript

@Bnaya ๋Š” ์ง€๊ธˆ ์šฐ๋ฆฌ๊ฐ€ ์›ํ•˜๋Š” ๊ฒƒ์ด ์™„์ „ํžˆ ์•„๋‹™๋‹ˆ๋‹ค. ;).
๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๊ตฌ์‹ Java๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ์‚ฌ์šฉํ•˜์ง€ ์•Š์„ ํด๋ž˜์Šค๋ฅผ ๋งŒ๋“ค์ง€ ์•Š๋„๋ก ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋Š” ํด๋ž˜์Šค๊ฐ€ ํ•ต์‹ฌ ๊ธฐ๋Šฅ์„ ๊ณ„์† ์ˆ˜ํ–‰ํ•˜๊ณ  ์ถ”๊ฐ€๋กœ ์ผ๋ฐ˜ํ™”๋œ ๊ธฐ๋Šฅ์„ ๊ตฌ์„ฑํ•  ์ˆ˜ ์žˆ๋Š” ๋งค์šฐ ๊นจ๋—ํ•˜๊ณ  ๊น”๋”ํ•œ ๊ตฌ์„ฑ ์•„ํ‚คํ…์ฒ˜๋ฅผ ํ—ˆ์šฉํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ, mixins๋Š” ํ•  ์ˆ˜ ์žˆ์ง€๋งŒ ๋ฐ˜์ฐฝ๊ณ ์ž…๋‹ˆ๋‹ค.

๋ฐ์ฝ”๋ ˆ์ดํ„ฐ ์ œ์•ˆ์ด ์ง€๋‚œ ๋ช‡ ๋‹ฌ ๋™์•ˆ ํฌ๊ฒŒ ๋ณ€๊ฒฝ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. TS ํŒ€์ด ๊ณง ํ˜ธํ™˜๋˜์ง€ ์•Š์„ ํ˜„์žฌ ๊ตฌํ˜„์— ์‹œ๊ฐ„์„ ํˆฌ์žํ•  ๊ฐ€๋Šฅ์„ฑ์€ ๋งค์šฐ ๋‚ฎ์Šต๋‹ˆ๋‹ค.

๋‹ค์Œ ๋ฆฌ์†Œ์Šค๋ฅผ ์‹œ์ฒญํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค.

๋ฐ์ฝ”๋ ˆ์ดํ„ฐ ์ œ์•ˆ: https://github.com/tc39/proposal-decorators
TypeScript ๋กœ๋“œ๋งต: https://github.com/microsoft/TypeScript/wiki/Roadmap

@Bnaya ๋Š” ์ง€๊ธˆ ์šฐ๋ฆฌ๊ฐ€ ์›ํ•˜๋Š” ๊ฒƒ์ด ์™„์ „ํžˆ ์•„๋‹™๋‹ˆ๋‹ค. ;).
๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๊ตฌ์‹ Java๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ์‚ฌ์šฉํ•˜์ง€ ์•Š์„ ํด๋ž˜์Šค๋ฅผ ๋งŒ๋“ค์ง€ ์•Š๋„๋ก ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋Š” ํด๋ž˜์Šค๊ฐ€ ํ•ต์‹ฌ ๊ธฐ๋Šฅ์„ ๊ณ„์† ์ˆ˜ํ–‰ํ•˜๊ณ  ์ถ”๊ฐ€๋กœ ์ผ๋ฐ˜ํ™”๋œ ๊ธฐ๋Šฅ์„ ๊ตฌ์„ฑํ•  ์ˆ˜ ์žˆ๋Š” ๋งค์šฐ ๊นจ๋—ํ•˜๊ณ  ๊น”๋”ํ•œ ๊ตฌ์„ฑ ์•„ํ‚คํ…์ฒ˜๋ฅผ ํ—ˆ์šฉํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ, mixins๋Š” ํ•  ์ˆ˜ ์žˆ์ง€๋งŒ ๋ฐ˜์ฐฝ๊ณ ์ž…๋‹ˆ๋‹ค.

๋ฏน์‹ฑ์ด ์•„๋‹ˆ๋ผ ํด๋ž˜์Šค์ž…๋‹ˆ๋‹ค.
๊ทธ ๋‚˜์œ ์นดํ”ผ-์žฌ๋ฃŒ ๋ฏน์Šค์ธ์ด ์•„๋‹™๋‹ˆ๋‹ค.
ํŒŒ์ดํ”„๋ผ์ธ ์—ฐ์‚ฐ์ž๊ฐ€ ๋„์ฐฉํ•˜๋ฉด ๊ตฌ๋ฌธ๋„ ํ•ฉ๋ฆฌ์ ์ž…๋‹ˆ๋‹ค.

mixin-class๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํ•ด๋‹น ํšจ๊ณผ๋ฅผ ์–ป์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

ํด๋ž˜์Šค ํŒฉํ† ๋ฆฌ ๋ฏน์Šค์ธ์€ TypeScript์—์„œ ๊ณ ํ†ต์Šค๋Ÿฌ์šธ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ ‡์ง€ ์•Š์€ ๊ฒฝ์šฐ์—๋„ ๋ฏน์Šค์ธ์œผ๋กœ ๋ณ€ํ™˜ํ•˜๊ธฐ ์œ„ํ•ด ํ•จ์ˆ˜์—์„œ ํด๋ž˜์Šค๋ฅผ ๋ž˜ํ•‘ํ•ด์•ผ ํ•˜๋ฏ€๋กœ ๋งค์šฐ ์ƒ์šฉ๊ตฌ์ ์ž…๋‹ˆ๋‹ค. ์ œ3์ž ํด๋ž˜์Šค๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ๊ฒฝ์šฐ ๊ฐ„๋‹จํžˆ ํ•  ์ˆ˜ ์—†๋Š” ๊ฒฝ์šฐ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

๋‹ค์Œ์€ ํ›จ์”ฌ ๋” ์ข‹๊ณ  ๊ฐ„๋‹จํ•˜๊ณ  ๊นจ๋—ํ•˜๋ฉฐ ๊ฐ€์ ธ์˜จ ํƒ€์‚ฌ ํด๋ž˜์Šค์™€ ํ•จ๊ป˜ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค. ๋ ˆ๊ฑฐ์‹œ ์Šคํƒ€์ผ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋ฅผ ๋ณ€ํ™˜ํ•˜๋Š” ๊ฒƒ ์™ธ์—๋Š” ๋ณ€ํ™˜ ์—†์ด ์ผ๋ฐ˜ JavaScript์—์„œ ์ œ๋Œ€๋กœ ์ž‘๋™ํ•˜์ง€๋งŒ class es๋Š” ์™„์ „ํžˆ ๊ธฐ๋ณธ class es๋กœ ์œ ์ง€๋ฉ๋‹ˆ๋‹ค.

class One {
    one = 1
    foo() { console.log('foo', this.one) }
}

class Two {
    two = 2
    bar() { console.log('bar', this.two) }
}

class Three extends Two {
    three = 3
    baz() { console.log('baz', this.three, this.two) }
}

@with(Three, One)
class FooBar {
    yeah() { console.log('yeah', this.one, this.two, this.three) }
}

let f = new FooBar()

console.log(f.one, f.two, f.three)
console.log(' ---- call methods:')

f.foo()
f.bar()
f.baz()
f.yeah()

๊ทธ๋ฆฌ๊ณ  Chrome์˜ ์ถœ๋ ฅ์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

1 2 3
 ---- call methods:
foo 1
bar 2
baz 3 2
yeah 1 2 3

์ด๊ฒƒ์€ ๋ชจ๋“  ์ƒ์šฉ๊ตฌ ์—†์ด ํด๋ž˜์Šค ํŒฉํ† ๋ฆฌ ๋ฏน์Šค์ธ์ด ํ•˜๋Š” ์ผ์„ ์™„์ „ํžˆ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ํด๋ž˜์Šค ์ฃผ๋ณ€์˜ ํ•จ์ˆ˜ ๋ž˜ํผ๋Š” ๋” ์ด์ƒ ํ•„์š”ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

๊ทธ๋Ÿฌ๋‚˜ ์•Œ๋‹ค์‹œํ”ผ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋Š” ์ •์˜๋œ ํด๋ž˜์Šค์˜ ์œ ํ˜•์„ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ๐Ÿ˜ข

๋”ฐ๋ผ์„œ ๋‹น๋ถ„๊ฐ„์€ ๋‹ค์Œ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋‹จ, ๋ณดํ˜ธ๋œ ๊ตฌ์„ฑ์›์€ ์ƒ์†ํ•  ์ˆ˜ ์—†๋‹ค๋Š” ์ ๋งŒ ์œ ์˜ํ•˜์‹ญ์‹œ์˜ค.

// `multiple` is similar to `@with`, same implementation, but not a decorator:
class FooBar extends multiple(Three, One) {
    yeah() { console.log('yeah', this.one, this.two, this.three) }
}

๋ณดํ˜ธ๋œ ๋ฉค๋ฒ„๋ฅผ ์žƒ๋Š” ๋ฌธ์ œ๋Š” multiple ๊ตฌํ˜„์˜ ๋‹ค์Œ ๋‘ ๊ฐ€์ง€ ์˜ˆ์—์„œ ์„ค๋ช…๋ฉ๋‹ˆ๋‹ค(์œ ํ˜•์— ๊ด€ํ•œ ํ•œ ํ•˜์ง€๋งŒ ๊ฐ„๊ฒฐํ•จ์„ ์œ„ํ•ด ๋Ÿฐํƒ€์ž„ ๊ตฌํ˜„์€ ์ƒ๋žต๋จ).

  • ๊ฒฐํ•ฉ๋œ ํด๋ž˜์Šค์˜ ๋ชจ๋“  ์†์„ฑ์ด ๊ณต์šฉ์ด๊ธฐ ๋•Œ๋ฌธ์— ์˜ค๋ฅ˜๊ฐ€ ์—†๋Š” ์˜ˆ์ œ์ž…๋‹ˆ๋‹ค .
  • ๋งคํ•‘๋œ ์œ ํ˜•์ด ๋ณดํ˜ธ๋œ ๋ฉค๋ฒ„๋ฅผ ๋ฌด์‹œํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์˜ค๋ฅ˜๊ฐ€ ์žˆ๋Š” ์˜ˆ (๋งจ ์•„๋ž˜์— ์žˆ์Œ), ์ด ๊ฒฝ์šฐ Two.prototype.two ๋ฅผ ์ƒ์†ํ•  ์ˆ˜ ์—†๊ฒŒ ๋งŒ๋“ญ๋‹ˆ๋‹ค.

๋ณดํ˜ธ๋œ ๋ฉค๋ฒ„๋ฅผ ํฌํ•จํ•˜์—ฌ ์œ ํ˜•์„ ๋งคํ•‘ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์ •๋ง ์›ํ•ฉ๋‹ˆ๋‹ค.

ํด๋ž˜์Šค๋ฅผ ํ•จ์ˆ˜๋กœ ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๊ฐ€ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์ด๊ฒƒ์€ ๋‚˜์—๊ฒŒ ์ •๋ง ์œ ์šฉํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์ด๊ฒƒ์€ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค:

export const MyClass = withFnConstructor(class MyClass {});

์ด๊ฒƒ์€ ์ž‘๋™ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค:

<strong i="10">@withFnConstructor</strong>
export class MyClass {}

์ด ๊ธฐ๋Šฅ์ด ๋‚˜์˜ฌ ๋•Œ ์ฒญ์†Œํ•˜๊ธฐ ์–ด๋ ต์ง€ ์•Š์€ ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•์€ ์„ ์–ธ ๋ณ‘ํ•ฉ ๋ฐ ์‚ฌ์šฉ์ž ์ง€์ • ์œ ํ˜• ์ •์˜ ํŒŒ์ผ์„ ์‚ฌ์šฉํ•˜์—ฌ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ด๋ฏธ ์ด๊ฒƒ์„ ๊ฐ€์ง€๊ณ :

// ClassModifier.ts
export interface Mod {
  // ...
}
// The decorator
export function ClassModifier<Args extends any[], T>(target: new(...args: Args) => T): new(...args: Args) => T & Mod {
  // ...
}
// MyClass.ts
<strong i="9">@ClassModifier</strong>
export MyClass {
  // ...
}

๋‹ค์Œ ํŒŒ์ผ์„ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค(๊ธฐ๋Šฅ์ด ๋‚˜์˜ค๋ฉด ์ œ๊ฑฐํ•  ํŒŒ์ผ).

// MyClass.d.ts
import { MyClass } from './MyClass';
import { Mod } from './ClassModifier';

declare module './MyClass' {
  export interface MyClass extends Mod {}
}

๋˜ ๋‹ค๋ฅธ ๊ฐ€๋Šฅํ•œ ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•

declare class Extras { x: number };
this.Extras = Object;

class X extends Extras {
   constructor() {  
      super(); 
      // a modification to object properties that ts will not pick up
      Object.defineProperty(this, 'x', {value: 3});
   }
}

const a = new X()
a.x // 3

2015๋…„์— ์‹œ์ž‘ํ–ˆ๊ณ  ์•„์ง ๋ณด๋ฅ˜ ์ค‘์ž…๋‹ˆ๋‹ค. ๋” ๋งŽ์€ ๊ด€๋ จ ๋ฌธ์ œ์™€ ์ด https://medium.com/p/caf24aabcb59/responses/show ์™€ ๊ฐ™์€ ๊ธฐ์‚ฌ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

๋ˆ„๊ตฐ๊ฐ€๊ฐ€ ์ด๊ฒƒ์— ๋Œ€ํ•ด ๋ฐํž ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ? ์•„์ง ๋‚ด๋ถ€ ๋…ผ์˜๋„ ๊ณ ๋ ค ์ค‘์ธ๊ฐ€?

tl;dr - ์ด ๊ธฐ๋Šฅ์€ TC39์—์„œ ๋ง‰ํ˜”์Šต๋‹ˆ๋‹ค. ์ด๊ฒƒ์— ๋Œ€ํ•ด TS ์‚ฌ๋žŒ๋“ค์„ ์ „ํ˜€ ๋น„๋‚œํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ํ‘œ์ค€์ด ๋  ๋•Œ๊นŒ์ง€ ๊ตฌํ˜„ํ•˜์ง€ ์•Š์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๊ทธ๋Ÿฌ๋‚˜ ์ด๊ฒƒ์€ Microsoft์ž…๋‹ˆ๋‹ค. ๊ทธ๋“ค์€ ๊ทธ๊ฒƒ์„ ๊ตฌํ˜„ํ•œ ๋‹ค์Œ ํ‘œ์ค€ ์‚ฌ๋žŒ๋“ค์—๊ฒŒ ๋งํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. "์‚ฌ๋žŒ๋“ค์ด ์ด๋ฏธ ์šฐ๋ฆฌ ๋ฒ„์ „์„ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค." :trollface:

์—ฌ๊ธฐ์„œ ๋ฌธ์ œ๋Š” TypeScript๊ฐ€ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋ฅผ ๊ตฌํ˜„ํ•œ ์ดํ›„๋กœ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ ์ œ์•ˆ์ด _์ƒ๋‹นํžˆ_ ๋ณ€๊ฒฝ๋˜์—ˆ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค(์ด์ „ ๋ฒ„์ „๊ณผ ํ˜ธํ™˜๋˜์ง€ ์•Š๋Š” ๋ฐฉ์‹์œผ๋กœ). ์ผ๋ถ€ ์‚ฌ๋žŒ๋“ค์€ TypeScript์˜ ํ˜„์žฌ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ ๋™์ž‘๊ณผ ์˜๋ฏธ ์ฒด๊ณ„์— ์˜์กดํ•˜๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์ƒˆ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๊ฐ€ ์™„์„ฑ๋˜๊ณ  ๊ตฌํ˜„๋  ๋•Œ ์ด๋Š” ๊ณ ํ†ต์Šค๋Ÿฌ์šด ์ƒํ™ฉ์œผ๋กœ ์ด์–ด์งˆ ๊ฒƒ์ž…๋‹ˆ๋‹ค. TypeScript ํŒ€์ด ์ด ๋ฌธ์ œ์— ๋Œ€ํ•œ ์กฐ์น˜๋ฅผ ํ”ผํ•˜๊ณ  ์‹ถ์–ดํ•  ๊ฒƒ์ด๋ผ๊ณ  ๊ฐ•๋ ฅํ•˜๊ฒŒ ์˜์‹ฌํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ ‡๊ฒŒ ํ•˜๋ฉด ํ˜„์žฌ์˜ ๋น„ํ‘œ์ค€ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋ฅผ ๋” ๋งŽ์ด ์‚ฌ์šฉํ•˜๊ฒŒ ๋˜์–ด ๊ถ๊ทน์ ์œผ๋กœ ์ƒˆ๋กœ์šด ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ ๊ตฌํ˜„์œผ๋กœ์˜ ์ „ํ™˜์ด ํ›จ์”ฌ ๋” ๊ณ ํ†ต์Šค๋Ÿฌ์šธ ๊ฒƒ์ด๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ๋ณธ์งˆ์ ์œผ๋กœ, ๋‚˜๋Š” ๊ฐœ์ธ์ ์œผ๋กœ ์ด๊ฒƒ์ด ์ผ์–ด๋‚˜๋Š” ๊ฒƒ์„ ๋ณด์ง€ ๋ชปํ•ฉ๋‹ˆ๋‹ค.

๋ง๋ถ™์—ฌ์„œ, ๋‚˜๋Š” ์ตœ๊ทผ์— ๊ฝค ๊ฒฌ๊ณ ํ•œ ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•์„ ์ œ๊ณตํ•  ๊ธฐ๋Šฅ์— ๋Œ€ํ•œ ์ œ์•ˆ์ธ #36348์„ ๋งŒ๋“ค์—ˆ์Šต๋‹ˆ๋‹ค. ์ž์œ ๋กญ๊ฒŒ ์‚ดํŽด๋ณด๊ณ /ํ”ผ๋“œ๋ฐฑ์„ ์ œ๊ณต/์•ผ๋งŒ ํ•ฉ๋‹ˆ๋‹ค. ๐Ÿ™‚

tl;dr - ์ด ๊ธฐ๋Šฅ์€ TC39์—์„œ ๋ง‰ํ˜”์Šต๋‹ˆ๋‹ค. ์ด๊ฒƒ์— ๋Œ€ํ•ด TS ์‚ฌ๋žŒ๋“ค์„ ์ „ํ˜€ ๋น„๋‚œํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ํ‘œ์ค€์ด ๋  ๋•Œ๊นŒ์ง€ ๊ตฌํ˜„ํ•˜์ง€ ์•Š์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์ด๋Ÿฌํ•œ ์‚ฌ์‹ค์„ ๊ฐ์•ˆํ•  ๋•Œ ๊ฐœ๋ฐœ ํŒ€์ด ๋น ๋ฅธ ์„ค๋ช…๊ณผ ์ƒํƒœ ์—…๋ฐ์ดํŠธ๋ฅผ ์ž‘์„ฑํ•˜๊ณ  TC39๊ฐ€ ์ด๋ฅผ ํ•„์š”ํ•œ ๋‹จ๊ณ„๋กœ ์ด๋™ํ•  ๋•Œ๊นŒ์ง€ ์ด ๋Œ€ํ™”๋ฅผ ์ž ๊ทธ๋Š” ๊ฒƒ์ด ํ˜„๋ช…ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ด ๊ธ€์„ ์ฝ๊ณ  ์žˆ๋Š” ๋ˆ„๊ตฐ๊ฐ€๊ฐ€ ์ด ๋ฌธ์ œ์— ๋ฌด๊ฒŒ๋ฅผ ๋‘๊ณ  ์žˆ์Šต๋‹ˆ๊นŒ?

์‚ฌ์‹ค, ๊ฑฐ์˜ ๋ชจ๋“  ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ์™€ ๊ด€๋ จ๋œ ๋Œ€ํ™”๊ฐ€ ๊ณต์ค‘์— ๋–  ์žˆ์Šต๋‹ˆ๋‹ค. ์˜ˆ: https://github.com/Microsoft/TypeScript/issues/2607

๋ฐ์ฝ”๋ ˆ์ดํ„ฐ์˜ ๋ฏธ๋ž˜์— ๋Œ€ํ•œ ๋ช…ํ™•์„ฑ์„ ์–ป๋Š” ๊ฒƒ์€ ๊ธฐ์—ฌ์ž์—๊ฒŒ ํ•„์š”ํ•œ ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ•˜๋„๋ก ์š”์ฒญํ•˜๋Š” ๊ฒƒ์ด๋”๋ผ๋„ ๋„์›€์ด ๋  ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋ช…ํ™•ํ•œ ์ง€๋„ ์—†์ด ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ์˜ ๋ฏธ๋ž˜๋Š” ํ๋ฆฟํ•˜๋‹ค

TypeScript ํŒ€์ด ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ ์ œ์•ˆ์— ๋Œ€ํ•œ ์ ๊ทน์ ์ธ ์—ญํ• ์„ ๋งก์„ ์ˆ˜ ์žˆ๋‹ค๋ฉด ์ข‹๊ฒ ์Šต๋‹ˆ๋‹ค. ์ €๋„ ๋•๊ณ  ์‹ถ์ง€๋งŒ ์•„์ง ์–ธ์–ด ๊ฐœ๋ฐœ ๋ถ„์•ผ์—์„œ ์ผํ•˜์ง€ ์•Š์•˜๊ธฐ ๋•Œ๋ฌธ์— ์–ด๋–ป๊ฒŒ ํ•˜๋ฉด ๊ฐ€์žฅ ์ข‹์„์ง€ ์ž˜ ๋ชจ๋ฅด๊ฒ ์Šต๋‹ˆ๋‹ค :-/

์ „์ฒด ํŒ€๊ณผ TypeScript๋ฅผ ํ”„๋กœ์ ํŠธ๋กœ ๋งํ•  ์ˆ˜๋Š” ์—†์ง€๋งŒ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ ๊ตฌํ˜„์ด TypeScript ๊ตฌํ˜„์—์„œ ์ด๋ฏธ ํ•œ ๋ฒˆ ๋ถ„๊ธฐ๋œ ๋ฐฉ์‹์„ ๊ณ ๋ คํ•  ๋•Œ ํ•ด๊ฒฐ๋˜๊ณ  ํ™•์ธ๋  ๋•Œ๊นŒ์ง€ ์ƒˆ๋กœ์šด ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•  ๊ฐ€๋Šฅ์„ฑ์€ ๊ฑฐ์˜ ์—†์Šต๋‹ˆ๋‹ค.

์ด ์ œ์•ˆ์€ ์—ฌ์ „ํžˆ โ€‹โ€‹ํ™œ๋ฐœํžˆ ๊ฐœ๋ฐœ ์ค‘์ด๋ฉฐ ์ด๋ฒˆ ์ฃผ์— TC39์— ์˜ฌ๋ผ์™”์Šต๋‹ˆ๋‹ค. https://github.com/tc39/proposal-decorators/issues/305

@orta ์ด ๊ฒฝ์šฐ ํด๋ž˜์Šค ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ์— ๋Œ€ํ•œ ๋ฌธ์„œ๋ฅผ ์—…๋ฐ์ดํŠธํ•ด์•ผ ํ•œ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๊ฒƒ์€ ๋งํ•œ๋‹ค

ํด๋ž˜์Šค ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๊ฐ€ ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•˜๋ฉด ํด๋ž˜์Šค ์„ ์–ธ์ด ์ œ๊ณต๋œ ์ƒ์„ฑ์ž ํ•จ์ˆ˜๋กœ ๋ฐ”๋€๋‹ˆ๋‹ค.

๋˜ํ•œ ๋ฌธ์„œ์˜ ๋‹ค์Œ ์˜ˆ์ œ๋Š” Greeter ์ธ์Šคํ„ด์Šค ์œ ํ˜•์— newProperty ์†์„ฑ์ด ์žˆ์Œ์„ ์•”์‹œํ•˜๋Š” ๊ฒƒ์œผ๋กœ ๋ณด์ž…๋‹ˆ๋‹ค. ์ด๋Š” ์‚ฌ์‹ค์ด ์•„๋‹™๋‹ˆ๋‹ค.

function classDecorator<T extends {new(...args:any[]):{}}>(constructor:T) {
    return class extends constructor {
        newProperty = "new property";
        hello = "override";
    }
}

<strong i="13">@classDecorator</strong>
class Greeter {
    property = "property";
    hello: string;
    constructor(m: string) {
        this.hello = m;
    }
}

console.log(new Greeter("world"));

๋ฐ˜ํ™˜๋œ ํด๋ž˜์Šค์˜ ์ธํ„ฐํŽ˜์ด์Šค๊ฐ€ ์›๋ž˜ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๋Œ€์ฒดํ•˜์ง€ ์•Š์„ ๊ฒƒ์ด๋ผ๋Š” ์ ์„ ๋ฌธ์„œ์— ์ถ”๊ฐ€ํ•  ๊ฐ€์น˜๊ฐ€ ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

ํฅ๋ฏธ๋กญ๊ฒŒ๋„ TypeScript์˜ ์—ฌ๋Ÿฌ ์ด์ „ ๋ฒ„์ „์„ ํ…Œ์ŠคํŠธํ–ˆ์ง€๋งŒ ํ•ด๋‹น ์ฝ”๋“œ ์ƒ˜ํ”Œ์ด ์ž‘๋™ํ•˜๋Š” ๊ฒฝ์šฐ๋ฅผ ์ฐพ์„ ์ˆ˜ ์—†์—ˆ์Šต๋‹ˆ๋‹ค( ์˜ˆ: 3.3.3 ). ์˜ˆ, ๋™์˜ํ•ฉ๋‹ˆ๋‹ค.

๋‚˜๋Š” https://github.com/microsoft/TypeScript-Website/issues/443 ์„ ๋งŒ๋“ค์—ˆ์Šต๋‹ˆ๋‹ค - ๋ˆ„๊ตฐ๊ฐ€๊ฐ€ classDecorator์— ๋ช…์‹œ์  ๊ต์ฐจ ์œ ํ˜•์„ ๊ฐ–๋„๋ก ๋งŒ๋“œ๋Š” ๋ฐฉ๋ฒ•์„ ์•Œ๊ณ  ์žˆ๋‹ค๋ฉด ํ•ด๋‹น ๋ฌธ์ œ์— ๋Œ€ํ•ด ์˜๊ฒฌ์„ ๋งํ•˜์‹ญ์‹œ์˜ค.

์œ„์— ๋‚˜์—ด๋œ ๋ฌธ์„œ์˜ ๋ฌธ์ œ๋กœ ์ธํ•ด ํ˜ผ๋ž€์ด ๋ฐœ์ƒํ–ˆ๊ธฐ ๋•Œ๋ฌธ์— ์—ฌ๊ธฐ์—์„œ ๋งˆ๋ฌด๋ฆฌํ–ˆ์Šต๋‹ˆ๋‹ค. ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ์—์„œ ๋ฐ˜ํ™˜๋œ ๊ฐ’์˜ ํ˜•์‹ ์„œ๋ช…์ด TS ์ปดํŒŒ์ผ๋Ÿฌ์—์„œ ์ธ์‹๋˜๋ฉด ์ข‹๊ฒ ์ง€๋งŒ ๋” ํฐ ๋ณ€๊ฒฝ ์‚ฌํ•ญ ๋Œ€์‹  ๋ฌธ์„œ๋ฅผ ๋ช…ํ™•ํ•˜๊ฒŒ ํ•ด์•ผ ํ•œ๋‹ค๋Š” ๋ฐ ๋™์˜ํ•ฉ๋‹ˆ๋‹ค.

๊ธฐ๋ก์„ ์œ„ํ•ด ์ด๊ฒƒ์€ @orta ์˜ PR์—์„œ ๊ด€๋ จ ๋ฌธ์„œ ํ˜•์‹์œผ๋กœ ์‹œ๋„ํ•œ ๊ฒƒ์˜ ๋‹จ์ˆœํ™”๋œ ๋ฒ„์ „์ž…๋‹ˆ๋‹ค.

interface HasNewProperty {
  newProperty: string;
}

function classDecorator<T extends { new (...args: any[]): {} }>(
  constructor: T
) {
  return class extends constructor implements HasNewProperty {
    newProperty = "new property";
    hello = "override";
  };
}

<strong i="8">@classDecorator</strong>
class Greeter {
  property = "property";
  hello: string;
  constructor(m: string) {
    this.hello = m;
  }
}

console.log(new Greeter("world"));

// Alas, this line makes the compiler angry because it doesn't know
// that Greeter now implements HasNewProperty
console.log(new Greeter("world").newProperty);
์ด ํŽ˜์ด์ง€๊ฐ€ ๋„์›€์ด ๋˜์—ˆ๋‚˜์š”?
0 / 5 - 0 ๋“ฑ๊ธ‰