์ด๊ฒ์ด ํ์ ๊ฒ์ฌ๋ฅผ ์ฌ๋ฐ๋ฅด๊ฒ ์ํํ ์ ์๋ค๋ฉด ์์ฉ๊ตฌ ์๋ ๋ฏน์ค์ธ์ ์๋ฒฝํ๊ฒ ์ง์ํ ์ ์์ต๋๋ค.
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'
๋ค์๊ณผ ๊ฐ์ ๋ฐฉ๋ฒ์๋ ์ ์ฉํฉ๋๋ค.
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)์ ๋นํด ๋ช ๊ฐ์ง ์ฅ์ ์ด ์์ต๋๋ค.
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๋ง ๋ค์ด๋ก๋๋ฅผ ๊ธฐ๋กํ๊ณ ์์ต๋๋ค. ๋น์ ์ด ๋ค๋ฅด๊ฒ ๊ตฌํํ์ ๊ฒ์ด๊ธฐ ๋๋ฌธ์ ๋์์ธ์ด ์ด๋ป๊ฒ๋ "ํ๋ ธ๋ค"๋ ๋ง์ ๋ฃ๋ ๊ฒ์ ๋ฏฟ์ ์ ์์ ์ ๋๋ก ์ค๋งํฉ๋๋ค.
์ ๋ฅผ ์ค๋งํ๊ฒ ํ๋ ๋ฑ ์ธ์ ๊ณต๊ฒฉ์ ์ผ๊ฐํด ์ฃผ์ญ์์ค.
connect()
ํจ์๋ ๋ด๊ฐ ์ ์ํ ๊ฒ์ฒ๋ผ HOC์ฒ๋ผ ๋ณด์
๋๋ค.ํ์ฌ ๋ฐ์ฝ๋ ์ดํฐ๊ฐ ๋์ ํ ๋ฉ์๋๋ฅผ ์ฌ์ฉํ๋ ค๋ ์๋๋ 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
๋ ์ก์ธ์คํ ์ ์๋๋ก ํ์ฉํฉ๋๋ค"๋ผ๊ณ ๋งํ ์ ์๋ค๋ฉด ์ ๋ง ์ข์ ๊ฒ์
๋๋ค.
์ด ์ค๋ ๋์ ๋ค๋ฅธ ๋ง์ ์ฌ๋๋ค์ด ๋น์ทํ ๋ฐ์ฝ๋ ์ดํฐ๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ผ๋ก ๋ณด์ด๋ฏ๋ก ์ด๊ฒ์ด ์๋ํ์ง ์์์ผ ํ๋ค๋ ๊ฒ์ด ์์์ด ์๋ ์๋ ์์์ ๊ณ ๋ คํ์๊ธฐ ๋ฐ๋๋๋ค.
@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 ์ ์๋ํฉ๋๊น? https://github.com/Zalastax/openschedule/blob/335ee3834122da7f65ba35f89d8fd737309fc4fb/src/components/week-selection/index.tsx _ .tsx
@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 ๊ทธ๊ฒ์ ๋๋ฅผ ์ํด ์๋ํ์ง ์์ต๋๋ค :
๋ด ์ฝ๋๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค. 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);
๊ฐ์ฅ ์ ์ฉํ ๋๊ธ
๋ค์๊ณผ ๊ฐ์ ๋ฐฉ๋ฒ์๋ ์ ์ฉํฉ๋๋ค.
๋น๋๊ธฐ ๋ฐ์ฝ๋ ์ดํฐ๋ ๋ฐํ ์ ํ์
Promise<any>
๋ก ๋ณ๊ฒฝํด์ผ ํฉ๋๋ค.