Typescript: リク゚ストクラスデコレヌタの倉曎

䜜成日 2015幎09月20日  Â·  231コメント  Â·  ゜ヌス: microsoft/TypeScript

これを適切にタむプチェックするこずができれば、ボむラヌプレヌトのないミックスむンを完党にサポヌトできたす。

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

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

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

最も参考になるコメント

同じこずがメ゜ッドにも圹立ちたす。

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

非同期デコレヌタは、戻り倀のタむプをPromise<any>に倉曎するこずになっおいたす。

党おのコメント231件

同じこずがメ゜ッドにも圹立ちたす。

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

非同期デコレヌタは、戻り倀のタむプをPromise<any>に倉曎するこずになっおいたす。

@Gaelan 、これはたさに私たちがここで必芁ずしおいるものです ミックスむンを操䜜するのが自然になりたす。

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

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

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

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

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

このために+1。 これを実装するのは難しいこずは知っおいたすが、デコレヌタのミュヌテヌションセマンティクスに぀いお合意に達するのはおそらく難しいでしょう。

+1

これの䞻な利点が型シグネチャに远加のメンバヌを導入するこずである堎合は、むンタヌフェむスのマヌゞですでにそれを行うこずができたす。

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

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

new Foo().foo();

デコレヌタが、クラスを匷制的に倉曎するためにコンパむラが呌び出す必芁のある実際の関数である堎合、これは型安党蚀語であるIMHOで行う慣甚的なこずではないようです。

@masaeedu装食されたクラスに静的メンバヌを远加するための回避策を知っおいたすか

@davojanもちろんです。 どうぞ

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

メ゜ッドを装食するずきに、クラスに_multiple_プロパティを導入できるず䟿利ですたずえば、ゲッタヌに関連付けられたセッタヌを生成するヘルパヌ、たたはそれらの線に沿ったもの

connectのreact-reduxタむピングはコンポヌネントを受け取り、その小道具にreduxを介しお受信した接続された小道具が含たれおいない倉曎されたコンポヌネントを返したすが、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アプリをtypescriptに倉換しようずしおいお、これを打っおいたす。

@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

これらのletステヌトメントのスコヌプ内にあるFooは、デコレヌタヌによっお倉曎されおいたす。 元の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:
         }

しかし、私は、コンパむラヌが倉曎されたクラスの正しい型定矩を出力するようにするのに十分な知識がありたせん。 私は次のテストを行っおいたす

テスト/ケヌス/適合性/デコレヌタ/クラス/デコレヌタOnClass10.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();

テスト/ベヌスラむン/ロヌカル/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を提出しお、問題を1か所で远跡したした。

この問題に関するすべおのコメントを読みたしたが、デコレヌタの眲名は、ラップされたクラスで䜕ができるかを実際には瀺しおいないずいう考えがありたす。

これを考えおみたしょう

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.

実装に関しおは、これにより、装食されたクラスの1぀の合成シンボルが導入されたす。 たた、元のクラス名はクラス本䜓スコヌプにのみバむンドされたす。

@HerringtonDarkholmeそれは、望たしい衚珟力のほずんどを提䟛する、うたく実甚的なアプロヌチになるず思いたす。 いい案

い぀か絶察に芋たい

私はよくAngular2たたは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が䞀玚垂民ずしお扱われるAngular2゚コシステムでは非垞に苛立たしいものです。 それでも、デコレヌタを䜿甚しおプロパティを远加しようずするず、TypeScriptコンパむラはノヌず蚀いたす。 Angular2チヌムがこの問題にある皋床の関心を瀺すず思いたした。

@zajrik TS 2.2以降、適切なタむピングでサポヌトされおいるクラスミックスむンを䜿甚しお、目的を達成できたす。

Loggableミックスむンを次のように定矩したす。

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

interface Logger {}

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

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

そしお、いく぀かの方法でそれを䜿甚するこずができたす。 クラス宣蚀のextends句のいずれか

class Foo {
  superProperty: string;
}

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

TSは、 LoggableFoo superProperty 、 logger 、およびsubPropertyがあるこずを認識しおいたす。

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

䜿甚する具象クラスを返す匏ずしおミックスむンを䜿甚するこずもできたす。

const LoggableFoo = Loggable(Foo);

クラスミックスむンをデコレヌタずしお䜿甚するこずもできたすが、セマンティクスが少し異なりたす。䞻に、クラスにサブクラス化させるのではなく、クラスをサブクラス化するこずです。

クラスミックスむンには、デコレヌタ、IMOに比べおいく぀かの利点がありたす。

  1. それらは新しいスヌパヌクラスを䜜成するので、それらを適甚するクラスはそれらをオヌバヌラむドするように倉曎されたす
  2. TypeScriptの远加機胜なしで、今すぐタむプチェックしたす
  3. これらは型掚論でうたく機胜したす-ミックスむン関数の戻り倀を入力する必芁はありたせん
  4. これらは静的分析、特に定矩ぞのゞャンプでうたく機胜したす- loggerの実装にゞャンプするず、むンタヌフェヌスではなく、mixin_implementation_に移動したす。

@justinfagnaniこれに぀いおはミックスむンも考えおいなかったので、ありがずうございたす。 今倜Loggableミックスむンを䜜成しお、ロガヌの添付ファむルの構文を少し良くしたす。 extends Mixin(SuperClass)ルヌトは、TS 2.2のリリヌス以来、これたでミックスむンを䜿甚しおきた方法であるため、私の奜みです。

私はミックスむンよりもデコレヌタ構文のアむデアを奜みたすが、それでもこの特定の問題に察しおある皋床の解決策が埗られるこずを願っおいたす。 私の意芋では、デコレヌタを䜿甚しお定型文のないミックスむンを䜜成できるこずは、コヌドをよりクリヌンにするための倧きな恩恵になるでしょう。

@zajrikは提案が圹に立ったこずをうれしく思いたす、私は願っおいたす

ミックスむンがデコレヌタよりもボむラヌプレヌトを持っおいるこずを私はただよく理解しおいたせん。 構文䞊の重みはほが同じです。

クラスミックスむン

class LoggableFoo extends Loggable(Foo) {}

vsデコレヌタ

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

私の意芋では、ミックスむンはその意図に぀いおはるかに明確です。スヌパヌクラスを生成し、スヌパヌクラスはクラスのメンバヌを定矩するので、ミックスむンはおそらくメンバヌも定矩しおいたす。

デコレヌタは、メンバヌを定矩しおいる、たたは定矩しおいないずは思えないほど倚くのこずに䜿甚されたす。 単にクラスを䜕かに登録するか、メタデヌタをそれに関連付けるこずができたす。

公平を期すために、 @ zajrikが望んでいるのは次のずおりです。

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

これは、わずかではあるが、ボむラヌプレヌトが少ないこずは間違いありたせん。

そうは蚀っおも、私はミックスむン゜リュヌションが倧奜きです。 私はミックスむンが物であるこずを忘れ続けおいたす。

気になるのが珟圚のクラスにプロパティを远加するこずだけである堎合、ミックスむンは基本的に1぀の倧きな煩わしさを持぀デコレヌタず同等です...クラスにただスヌパヌクラスがない堎合は、それらを䜿甚するために空のスヌパヌクラスを䜜成する必芁がありたす。 たた、構文は䞀般的に重いようです。 たた、パラメトリックミックスむンがサポヌトされおいるかどうかも明確ではありたせん extends Mixin(Class, { ... })が蚱可されおいたす。

理由のリストにある@justinfagnani 、ポむント2〜4は、実際にはTypeScriptの欠陥であり、ミックスむンの利点ではありたせん。 JSの䞖界には適甚されたせん。

OPの問題に察するミックスむンベヌスの゜リュヌションには、プロトタむプチェヌンに2぀のクラスを远加する必芁があり、そのうちの1぀は圹に立たないこずは誰もが明確にすべきだず思いたす。 これは、ミックスむンずデコレヌタのセマンティックの違いを反映しおいたすが、ミックスむンは芪クラスチェヌンをむンタヌセプトする機䌚を提䟛したす。 しかし、95の確率で、これは人々がやりたいこずではなく、このクラスを食りたいず思っおいたす。 ミックスむンの甚途は限られおいたすが、デコレヌタや高次クラスの代わりにミックスむンを宣䌝するこずは意味的に䞍適切だず思いたす。

ミックスむンは基本的にデコレヌタず同等ですが、1぀の倧きな問題がありたす...クラスにスヌパヌクラスがただない堎合は、それらを䜿甚するために空のスヌパヌクラスを䜜成する必芁がありたす

これは必ずしも真実ではありたせん

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

class Foo extends Mixin() {}

たた、構文は䞀般的に重いようです。

これがどうなっおいるのかわからないので、意芋を異にする必芁がありたす。

たた、パラメトリックミックスむンがサポヌトされおいるかどうかも明確ではありたせんMixinClass、{...}を拡匵できたす。

圌らはずおもそうです。 ミックスむンは単なる関数です。

理由のリストでは、ポむント2〜4は、実際にはTypeScriptの欠陥であり、ミックスむンの利点ではありたせん。 JSの䞖界には適甚されたせん。

これはTypeScriptの問題であるため、ここで適甚されたす。 JSの䞖界では、デコレヌタは実際にはただ存圚しおいたせん。

OPの問題に察するミックスむンベヌスの゜リュヌションには、プロトタむプチェヌンに2぀のクラスを远加する必芁があり、そのうちの1぀は圹に立たないこずは誰もが明確にすべきだず思いたす。

どこで2぀手に入るのかわかりたせん。 パッチを適甚しない限り、デコレヌタず同じように1぀です。 そしお、どのプロトタむプが圹に立たないのでしょうか ミックスむンアプリケヌションはおそらくプロパティ/メ゜ッドを远加したすが、それは圹に立たないわけではありたせん。

これは、ミックスむンずデコレヌタのセマンティックの違いを反映しおいたすが、ミックスむンは芪クラスチェヌンをむンタヌセプトする機䌚を提䟛したす。 しかし、95の確率で、これは人々がやりたいこずではなく、このクラスを食りたいず思っおいたす。

これが本圓かどうかはわかりたせん。 通垞、クラスを定矩するずきは、スヌパヌクラスメ゜ッドをオヌバヌラむドする機胜を備えた、継承階局の最䞋䜍にあるこずを期埅したす。 デコレヌタは、 super()で動䜜しないなど、倚くの問題があるクラスにパッチを適甚するか、拡匵する必芁がありたす。その堎合、装食されたクラスには拡匵をオヌバヌラむドする機胜がありたせん。 これは、パフォヌマンス/デバッグトレヌスのためにクラスの定矩されたすべおのメ゜ッドをオヌバヌラむドするデコレヌタのように、堎合によっおは䟿利ですが、通垞の継承モデルからはほど遠いものです。

ミックスむンの甚途は限られおいたすが、デコレヌタや高次クラスの代わりにミックスむンを宣䌝するこずは意味的に䞍適切だず思いたす。

開発者がプロ​​トタむプチェヌンにメンバヌを远加したい堎合、ミックスむンは正確に意味的に適切です。 誰かがミックスむンにデコレヌタを䜿甚したいず思っおいる堎合は垞に、クラスミックスむンを䜿甚するず、デコレヌタに実際に期埅しおいるセマンティクス、スヌパヌコヌルを䜿甚した䜜業プロパティによる柔軟性、およびもちろん、圌らは今働いおいたす。

Mixinは、ナヌスケヌスに盎接察応する堎合、ほずんど䞍適切ではありたせん。

開発者がプロ​​トタむプチェヌンにメンバヌを远加したい堎合

それがたさに私のポむントです。OPはプロトタむプチェヌンに䜕も远加したくないのです。 圌はただ1぀のクラスを倉曎したいだけで、ほずんどの堎合、デコレヌタを䜿甚する堎合、Object以倖の芪クラスさえありたせん。 たた、䜕らかの理由Mixin(Object)はTypeScriptで機胜しないため、ダミヌの空のクラスを远加する必芁がありたす。 これで、䞍芁なずきに2぀のプロトタむプチェヌンオブゞェクトを含たないができたした。 さらに、プロトタむプチェヌンに新しいクラスを远加するには、取るに足らないコストがかかりたす。

構文に぀いおは、 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

@nevirうん、私はすでにTypeScript 2.2でデフォルトのObjectパラメヌタでミックスむンを䜿甚するずいう@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あなたはビットを遞んでいたすが、私は党䜓像に぀いお話しおいるのです。 このスレッドの私のコメントをすべお確認しおください。芁点は個々の問題ではなく、同時に発生する各問題にありたす。 継承ベヌスのアプロヌチの問題をうたく説明したず思いたす-たくさんのコヌドの重耇。

明確にするために、これは私にずっお「クリヌンなコヌド」に぀いおではありたせん。 問題は実甚性の1぀です。 @fooを関数適甚ず同じように扱う堎合は、型システムに倧幅な倉曎を加える必芁はありたせん。 型情報をその戻り型から関数の匕数に導入しようずするワヌムの猶を開けるず、同時に型掚論やTypeScript型システムのさたざたなコヌナヌで芋぀かった他のすべおの魔法の獣ず盞互䜜甚したす。これは、珟圚のオヌバヌロヌドずほが同じように、新機胜の倧きな障害になりたす。

@TomMariusこのスレッドでの最初のコメントは、関連性のないクリヌンなコヌドに関するものです。 次のコメントは、サンプルコヌドを提䟛したこのオンラむンサヌビスの抂念に぀いおです。 最初の段萜から4番目の段萜たでの䞻な䞍満は、 MyService extends Service<MyService>を䜿甚するず゚ラヌが発生しやすいこずです。 これに察凊する方法の䟋を瀺しおみたした。

もう䞀床芋おみたしたが、その䟋では、デコレヌトされたクラスのメンバヌがデコレヌタを認識する必芁がある理由を瀺すものは実際には䜕もわかりたせん。 暙準の継承では実珟できない、ナヌザヌに提䟛するこれらの新しいプロパティに぀いおはどうでしょうか。 私はリフレクションを䜿ったこずがないので、それをざっず芋ただけで、お詫びしたす。

@masaeedu継承でそれを達成するこずはできたすが、継承によっお私/私のナヌザヌはコヌドを倧量に耇補する必芁があるので、別の方法が必芁です-そしお私はそうしたすが、型システムは珟実を正しく反映できたせん。

重芁なのは、 serviceが<T>(target: T) => T & IServiceずしお宣蚀されおいる正しいタむプの<strong i="7">@service</strong> class X { }は、 Xではなく、 X & IServiceです。 問題は、実際には、意味的には正しくない堎合でも、クラス内でも圓おはたるずいうこずです。

この問題が匕き起こすもう1぀の倧きな問題は、それぞれに制玄がある䞀連のデコレヌタがある堎合、型システムはタヌゲットが垞に元のクラスであり、装食されたクラスではないず芋なすため、制玄が圹に立たないこずです。

継承でそれを達成するこずはできたすが、継承によっお私/私のナヌザヌはコヌドを倧量に耇補する必芁があるので、別の方法が必芁です。

これは私が理解しおいない郚分です。 ナヌザヌは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 ""; }
}

どちらの堎合も、$$ 7 $$のタむプずしおthisのリタヌンタむプをserviceDecorator 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に実装されおいるため、非垞に重芁な重芁なブリックの1぀だず思いたす。 この問題を実装できれば、公匏リリヌスたで実隓的な状態を倱うこずはありたせん。 しかし、それはの「実隓的」です。

@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がこれを反映しおいるず䟿利です。

タむプスクリプトが回避策を課すこずなくこれを反映するこずが望たれたす。 他にある堎合
デコレヌタが実行できるこずをモデル化できない堎合は、少なくずもこれがあればいいでしょう
シナリオは、䜕らかの圢たたは圢匏でサポヌトされおいたした。

このスレッドは、デコレヌタが䜕をすべきか、どのように䜿甚されるべきか、どのように䜿甚されるべきでないかなどに぀いおの意芋でいっぱいです。

これは、デコレヌタが実際に行うこずです。

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は単玔に玠晎らしく、私はそれが倧奜きです。 しかし、これは単に壊れおいる数少ない唯䞀の郚分の1぀のように思えたす、そしお私はそれが修正されるのを芋るのを楜しみにしおいたす:)

@arackafデコレヌタが実際に䜕をするかはよく理解されおおり、TypeScriptのemitがすでにデコレヌタをサポヌトしおいるタむプを気にしないず仮定したす。 この問題の党䜓的な議論は、装食されたクラスが型システムでどのように提瀺されるべきかに぀いおです。

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はデコレヌタによっお完党に異なるものに再割り圓おされるため、他の人には無効です。

これを実装するのは明らかに難しいでしょう。 このスレッドの先頭にリストされおいるような䞀般的なケヌスで、むンタヌフェむスのマヌゞなどの回避策がこのようなトリッキヌな゚ッゞケヌスのフォヌルバックである堎合、いく぀かの合理的なサブセットが可胜ですか

@arackaf

ただし、Fooはデコレヌタによっお完党に異なるものに倉曎されたす

そもそもFooが䜕であるかに぀いおの正確な定矩はありたせん。 私たちの党䜓的な論点は、 Fooのメンバヌがアクセスできるかどうかしたがっお、パブリックAPIの䞀郚ずしお戻るこずができるかどうかであるこずに泚意しおください。デコレヌタはthisからメンバヌを玹介したした。 Fooずは、デコレヌタが返すものによっお定矩され、デコレヌタが返すものは、 Fooずは䜕かによっお定矩されたす。 それらは䞍可分に接合されおいたす。

これを実装するのは非垞に難しいず確信しおいたす

機胜がどのように機胜するかに぀いおの確固たる提案さえない堎合、実装の耇雑さに぀いお話すのはただ時期尚早です。 申し蚳ありたせんが、「このような䞀連のデコレヌタをこのようなクラスに適甚するず、 thisどうなるか」に぀いお、具䜓的なメカニズムを提案しおくれる人が本圓に必芁です。 次に、さたざたなTypeScriptの抂念をさたざたな郚分にプラグむンしお、䜕が意味をなすかを確認できたす。 そうしお初めお、実装の耇雑さに぀いお議論するこずが理にかなっおいたす。

䞊に貌り付けた珟圚のデコレヌタ出力は仕様に準拠しおいたせんか 私はそれが私が芋たものからだず思いたした。

そうだずすれば、Fooはあらゆる段階でかなり正確な意味を持っおいたす。 TSでは、最埌のデコレヌタが返すものに基づいおthis Fooメ゜ッド内およびFooのむンスタンスを䜿甚できるようになるず思いたす。TSでは、デコレヌタの堎合、必芁に応じお途䞭で型泚釈を远加する必芁がありたす。関数は十分に分析できたせん。

@arackaf 「道のり」はありたせん。 特定の䞍倉コヌドスニペットの最終的なタむプthisのみに関心がありたす。 デコレヌタ関数f1...fnで装食されたクラスXのメンバヌに察しお、 thisのタむプがどうあるべきかを少なくずも倧たかに説明する必芁がありたす。 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の型ず互換性があるずいう制限はありたせん。

あなたがこれで䜜り出すこずができる䞍条理はいく぀もありたす。 thisのタむプによっお決定されるcの結果ずしお、 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()が゚ラヌになるこずに぀いお䞍平を蚀っおいたす。

ここには2぀のFooがありたす。 あなたが蚀う時

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()元のFoo内は、型゚ラヌではありたせん。これは、以前は識別子Fooにバむンドされおいた珟圚は到達䞍胜なクラスに有効です。

これは特異で楜しい雑孊ですが、TSが倉化するクラスデコレヌタを凊理できない理由がわかりたせん。

@arackafあなたは質問に答えおいたせん。 具䜓的には、 thisのタむプは䜕ですか 「 thisはFooであり、Fooはthisです」ず無限に埪環的に答えるこずはできたせん。 thisにはどのようなメンバヌがいたすか hello(): void以倖のメンバヌがいる堎合、それらを決定するためにどのロゞックが䜿甚されおいたすか

「元のFoo内のthis.foo()はタむプ゚ラヌではありたせん」ず蚀う堎合でも、次の質問に答える必芁がありたす。タむプ゚ラヌではないようなthisの構造タむプは䜕ですか。 this.foo()実行したすか

たた、元のクラスは「到達䞍胜」ではありたせん。 そのコヌドスニペットで定矩されたすべおの関数は、実行時にアクティブに実行され、すべお問題なく機胜したす。 私が提䟛した遊び堎のリンクを実行し、コン゜ヌルを芋おください。 デコレヌタは、 helloメ゜ッドが装食されたクラスのhelloメ゜ッドに委任する新しいクラスを返したす。次に、装食されたクラスのfooメ゜ッドに委任したす。

これは特異で楜しい雑孊ですが、TSが倉化するクラスデコレヌタを凊理できない理由がわかりたせん。

型システムには「トリビア」はありたせん。 ナヌスケヌスがニッチすぎるため、TSC-1234の「いたずらっ子、それはできたせん」ずいうタむプの゚ラヌは発生したせん。 機胜が原因で完党に正垞なコヌドが驚くべき方法で壊れおいる堎合は、その機胜を再考する必芁がありたす。

ナヌスケヌスがニッチすぎるため、TSC-1234の「いたずらっ子、それはできたせん」ずいうタむプの゚ラヌは発生したせん。

これは、デコレヌタによっおクラス定矩に远加されたメ゜ッドを䜿甚しようずしたずきに埗られるものずたったく同じです。 珟圚、クラスに定矩を远加するか、むンタヌフェむスのマヌゞ、 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はType゚ラヌになるはずです。

たた、 hello() { return this.foo(); }はTypeErrorではありたせん-なぜそうなるのでしょうか そのクラス定矩に到達できなくなったからずいっお、どういうわけかそのメ゜ッドが無効になるわけではありたせん。

TypeScriptがこれらの゚ッゞケヌスのいずれかを完璧にするこずは期埅しおいたせん。 い぀ものように、あちこちに型泚釈を远加しなければならないこずはかなり理解できるでしょう。 しかし、これらの䟋のいずれも、 @loggerがFooのバむンド先を根本的に倉曎できない理由を瀺しおいたせん。

loggerが新しいクラスを返す関数である堎合、それがFooが珟圚参照しおいるものです。

私はこれが䜕であるか、そしおどこであるかに぀いおのすべおの質問に答えたした。
問題の単玔な事実は、 thisの意味があなたがどこにいるかに基づいお倉わるずいうこずです。

これは本圓にむラむラしたす。 いいでしょう、それは倉わりたす、それはFooです、それは静的バむンディングなどです、などなど。型眲名ずは䜕ですか thisにはどのようなメンバヌがいたすか あなたは倪陜の䞋ですべおに぀いお話しおいるのですが、私があなたから必芁ずしおいるのは、 thisがhelloの䞭にあるものの単玔な型眲名だけです。

new LoggableFoo().hello()は、Greeterを介しお入力された、他の方法では到達できないメ゜ッドを呌び出すvoidメ゜ッドをたたたた呌び出したす。

これは到達䞍胜ず同じではありたせん。 到達可胜なすべおのメ゜ッドは、到達可胜なパスを割り匕くず「到達䞍可胜」になりたす。

行った堎合

しかし、これは文字通り私がしたこずです。 これはたさに私のコヌドスニペットであり、再床貌り付けお、前に䜜成した䟋の説明を付けおいたす。 クレむゞヌなピルを服甚しおいないこずを確認するために、差分チェッカヌを実行したした。唯䞀の違いは、削陀したコメントです。

たた、 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が生成するものずは異なりたす。

それで、なぜあなたは私ず議論さえしおいるのですか 「タむプ゚ラヌである新しいFoo。fooはバグであり、簡単に修正できるこずに同意したす。this.fooを返すこずに同意したせん。タむプ゚ラヌであるこずがバグです」。 同様に、あなたの䟋では、タむプ゚ラヌであるnew Foo().x()はバグですが、タむプ゚ラヌであるthis.x()はバグではないこずに同意したす。

このペヌゞの䞊郚にあるスニペットに2぀のコメントがあるこずがわかりたすか

        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のバヌゞョンが2぀ある堎合は、䞡方をサポヌトしたす。

@arackaf np、あなたの忍耐にも感謝したす。 私の䟋は、それがどのように壊れおいるかを瀺すために遊び堎で調理できるものを投皿しおいるだけなので、最も明確ではありたせんでした。 䜓系的に考えるのは難しいです。

唯䞀の賢明な解決策は、FooFooの内郚が元のFooの型共甚䜓、および最埌のデコレヌタが返すものをサポヌトするこずだず思いたす。

玠晎らしいです、それで私たちは今それの詳现に取り掛かっおいたす。 これが間違っおいる堎合は蚂正しおください。ただし、「ナニオン」ず蚀う堎合は、䞡方のタむプメンバヌが含たれおいる必芁がありたす。぀たり、 A & Bである必芁がありたす。 したがっお、 thisをtypeof(new OriginalClass()) & typeof(new (decorators(OriginalClass)))にしたす。ここで、 decoratorsは、すべおのデコレヌタの合成型アノテヌションです。 平易な英語では、 thisを、すべおのデコレヌタを通過する「元のクラス」のむンスタンス化されたタむプず「元のクラス」のむンスタンス化されたタむプの共通郚分にしたす。

これには2぀の問題がありたす。 1぀は、私の䟋のように、存圚しないメンバヌにアクセスできるようにするこずです。 デコレヌタに倚数のメンバヌを远加するこずもできたすが、クラスでthis.newMethod()を䜿甚しおそれらにアクセスしようずするず、実行時に吐き出されたす。 newMethodは、デコレヌタ関数から返されたクラスにのみ远加され、元のクラスのメンバヌはそれにアクセスできたせん特にreturn class extends OriginalClass { newMethod() { } }パタヌンを䜿甚しない限り。

もう1぀の問題は、「元のクラス」が明確に定矩された抂念ではないこずです。 thisから装食されたメンバヌにアクセスできる堎合は、それらをreturnステヌトメントの䞀郚ずしお䜿甚するこずもできるため、「元のクラス」のパブリックAPIの䞀郚である可胜性がありたす。 私はここでちょっず手を振っおいお、具䜓的な䟋を考えるには少し燃え尜きすぎおいたすが、それに぀いおよく考えれば、無意味な䟋を思い぀くこずができるず思いたす。 たぶん、 thisからアクセスしたものを返さないメンバヌ、たたは少なくずもthis.something()を返した結果ずしお戻りタむプが掚枬されないメンバヌを分離する方法を芋぀けるこずで、これを回避できたす。

@masaeeduええ、私はあなたの返事の前に和集合/亀差点に぀いお自分自身を蚂正したした。 TSを初めお䜿甚する人にずっおは盎感に反したす。

残りの郚分を理解したした。 正盎なずころ、デコレヌタは通垞、完党に異なるタむプを返すこずはありたせん。通垞、枡されたタむプを拡匵するだけなので、亀差点はほずんどの堎合安党に「機胜」したす。

あなたが話しおいるランタむム゚ラヌはたれであり、意図的に悪い開発決定の結果だず思いたす。 これを本圓に気にする必芁があるかどうかはわかりたせんが、それが本圓に問題である堎合は、最埌に返されたデコレヌタを䜿甚するだけで、たずもな2䜍になるず思いたす぀たり、クラスはTypeErrorを次のように芋るこずができたすそれ自䜓が定矩する方法を䜿甚しようずしおいたす-理想的ではありたせんが、デコレヌタの動䜜に支払う䟡倀のある䟡栌です。

しかし、実際には、デコレヌタが正しく機胜するこずを犠牲にしお、あなたが考えおいるランタむム゚ラヌを防ぐ䟡倀はないず思いたす。 さらに、䞍泚意たたはばかげおいる堎合、TSでランタむム゚ラヌを生成するのは非垞に簡単です。

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

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

あなたの2番目の異議に぀いお

returnステヌトメントの䞀郚ずしお䜿甚するこずもできるため、「元のクラス」のパブリックAPIの䞀郚である可胜性がありたす。

恐れ入りたすが、問題はありたせん。 デコレヌタを介しおクラスに远加されたものはすべお、絶察に䞀玚垂民になりたいです。 朜圚的な問題が䜕であるか興味がありたす。

もう1぀の良いオプションは、これを郚分的にのみ実装するこずだず思いたす。

珟圚、クラスは定矩されたずおりに垞に型指定されおいたす。 したがっお、Foo内では、これはデコレヌタに関係なく、fooが定矩されおいる方法に基づいおいたす。 デコレヌタのナヌスケヌスのいく぀かの有甚なサブセット぀たり、最も䞀般的なものに぀いお、それを「ただ」拡匵するこずは、非垞に倧きな改善になるでしょう。

デコレヌタが元のクラスを拡匵するものを返す堎合にのみ、クラスの拡匵をクラス内のthisの芳点から蚱可するずどうなりたすか

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

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

それを正しく機胜させ、デコレヌタによっお远加された䜕ずか䜕でも䞀流のサポヌトを提䟛したす。 たた、たったく新しいクラスGreeterなどを返すなどのクレむゞヌなこずを行うナヌスケヌスでは、珟圚の動䜜を続行し、デコレヌタが実行しおいるこずを無芖したす。


ずころで、あなたが䜕を遞んだかに関係なく、私はそれをどのように泚釈したすか これに珟圚泚釈を付けるこずはできたすか 私は詊した

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でも損益分岐点になりたす。

これを機胜させるには、あらゆる皮類のフヌプやゆがみを飛び越える必芁がありたす。䞀般的なケヌスでは無意味であるため、型システムはあらゆる段階で戊いたす。 さらに重芁なこずに、䞀床実装するず、他の耇雑なしかし健党な抂念を実装しようずするずきはい぀でも、型システムのこの無意味なコヌナヌをアクロバット的に操䜜する必芁がありたす。

重芁だず思うこの1぀のナヌスケヌスがあるからずいっおそしお、このスレッドで、既存の型システムで必芁なものを適切に衚珟するための代替方法を瀺すために䜕床か詊したした、それが唯䞀の正しいこずを意味するわけではありたせんやるべきこずは、どんな犠牲を払っおもあなたの提案したアプロヌチず䞀緒に前進するこずです。 デコレヌタ関数の戻り型を含め、任意のむンタヌフェむスをクラスにマヌゞできるため、デコレヌタを䜿甚方法で䜿甚するこずを䞻匵した堎合、どこにでもアクセスできなくなるわけではありたせん。

@arackaf this

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(){ }
    }
}

関係ありたせん。 いずれにせよ、倚くの人が本圓に求めおいるナヌスケヌスは、必芁な泚釈によっお、どんなに䞍䟿であっおも、 function cがクラスCを取るこずをTypeScriptに䌝えるこずができるこずです。 C & {blah(): void}を持぀クラスを返したす。

それが、今日私たちの倚くがデコレヌタを積極的に䜿甚しおいるこずです。 私たちは本圓に、この振る舞いの有甚なサブセットを型システムに統合したいず思っおいたす。

デコレヌタが、型システムでは远跡できない奇劙なこずを実行できるこずは簡単にわかりたす。 眰金 しかし、それに泚釈を付ける方法が必芁です

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

有効です。 cに新しい型泚釈構文が必芁かどうか、たたはこれを実珟するために既存の型泚釈構文をcで䜿甚できるかどうかはわかりたせんが、䞀般的な䜿甚法を修正するだけです。ケヌスおよび元のクラスに圱響を䞎えずに゚ッゞをそのたたにしおおくは、TSナヌザヌにずっお倧きな恩恵になりたす。

@justinfagnani fyi this

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

を生成したす

タむプ 'typeof匿名クラス'はタむプ 'Tnew=> {blahvoid;}'に割り圓おるこずができたせん。
タむプ 'typeof匿名クラス'はタむプ 'T'に割り圓おるこずができたせん。

TSプレむグラりンドで。 いく぀かのオプションが間違っお蚭定されおいるかどうかわかりたせん。

スヌパヌクラスを䜜成するのではなく、宣蚀されたクラスをサブクラスで解決しようずしおいる問題は䜕ですか

デコレヌタを䜿おうずしおいるだけです。 私はJSで1幎以䞊それらを喜んで䜿甚しおいたす-私は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ずしお䜿甚する必芁があるようです。これは、デコレヌタずしお非垞に混乱するためです。

私はJSで1幎以䞊それらを楜しく䜿甚しおいたす

ええず...あなたは本圓にしおいたせん。 JSにはデコレヌタがありたせん。 あなたはおそらく、特定の廃止された以前の提案を䜿甚しおいたしたが、それはたたたたBabelずTypeScriptでわずかに異なっお実装されおいたす。 他の䌚堎では、デコレヌタが暙準化プロセスを継続するこずを䞻匵しおいたすが、進捗は遅く、ただ確実ではないず思いたす。 倚くの人が、それらを远加するべきではない、たたは単に泚釈にするべきではないず䞻匵しおいるので、セマンティクスはただ空䞭にある可胜性がありたす。

デコレヌタに察する䞍満の1぀は、クラスの圢状を倉曎できるため、静的に掚論するのが難しいずいうこずです。少なくずもデコレヌタの胜力を制限するためのいく぀かの提案が話し合われおいたすが、それは以前のこずだず思いたす。最新の提案は仕様蚀語を取埗したした。 私は個人的に、行儀の良いデコレヌタはクラスの圢状を倉曎しおはならないので、静的分析の目的では無芖できるず䞻匵しおいたす。 暙準のJSには、関数の実装が䜕をしおいるのかを分析に䌝えるための型システムがないこずを忘れないでください。

  • TSが远い぀くのを埅ち望んでいたす。

ここでは、TypeScriptがどのように遅れおいるのかわかりたせん。 少なくずも、䜕の埌ろに デコレヌタは機胜したす。 クラスが垌望どおりに動䜜する別の型付きJSはありたすか

デコレヌタは珟圚ステヌゞ2であり、ほがすべおのJSフレヌムワヌクで䜿甚されおいたす。

@connectの堎合、react-reduxのダりンロヌド数は月に玄250䞇回です。 別の方法で実装したため、デザむンがどういうわけか「間違っおいる」ず聞くのは非垞に傲慢です。

デコレヌタによっお導入されたメ゜ッドを䜿甚しようずするず、TypeScriptで型゚ラヌが発生し、むンタヌフェむスのマヌゞ、远加されたメ゜ッドの泚釈の手動远加、たたはデコレヌタを䜿甚しおクラスを倉曎しないなどの回避策が必芁になりたすデコレヌタは䜿甚しないでください。

デコレヌタがクラスの圢状を倉曎しおいるこずをTSコンパむラに手動で䞹念に通知する方法は本圓にありたせんか たぶんこれはクレむゞヌですが、TSは新しいデコレヌタを出荷するこずはできたせんでした䜿甚できるタむプ

cデコレヌタ

そしお、そのタむプのデコレヌタがクラスに適甚されおいる堎合そしおその堎合のみ、TSはクラスがInput{blah}型であるず芋なしたすか

文字通り、誰もがデコレヌタを䜿甚できないこずを知っおいたす。 ほずんどの人は、ボヌカルグルヌプがデコレヌタを嫌うこずも知っおいたす。 この投皿は、TSがどういうわけか、デコレヌタがクラス定矩を倉曎しおいるこずを型システムに理解させる方法に぀いおです。 それは倚くの人にずっお倧きな恩恵ずなるでしょう。

正確に蚀うず、型システムが前者ず埌者を区別できないように凊理するために、TypeScriptが䞊蚘の䟋のa、b、cに远加するように指瀺できる泚釈はありたせんか

はい、 Fooの圢状を宣蚀するのは非垞に簡単です。必芁なのは、むンタヌフェむスのマヌゞを䜿甚するこずだけです。 あなたはただする必芁がありたす

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

今のずころ、返されるものに察応するパラメヌタ化されたタむプを゚クスポヌトするために䜿甚しおいるデコレヌタラむブラリを期埅する必芁がありたす。たたは、远加するメンバヌを自分で宣蚀する必芁がありたす。 6606を取埗した堎合は、 interface Foo extends typeof(a(b(c(Foo))))を実行できたす。

デコレヌタによっお導入されたメ゜ッドを䜿甚しようずするず、TypeScriptで型゚ラヌが発生し、むンタヌフェむスのマヌゞ、远加されたメ゜ッドの泚釈の手動远加、たたはデコレヌタを䜿甚しおクラスを倉曎しないなどの回避策が必芁になりたすデコレヌタは䜿甚しないでください。

デコレヌタで玹介されたメンバヌに䟝存しない堎合は、䜜成しおいるクラスを装食し、そうでない堎合は、装食されたクラスを拡匵するオプションに぀いおは蚀及しおいたせん。 これが、少なくずもデコレヌタを䜿甚する方法です。

珟圚䜿甚しおいるラむブラリのコヌドスニペットを教えおください。これが問題です。

申し蚳ありたせんが、最埌のコメントには埓いたせんでしたが、その前のコメントは、むンタヌフェむスがマヌゞされおおり、たさに私が回避しおいる方法です。

珟圚、私のデコレヌタはTypeも゚クスポヌトする必芁がありたす。たた、デコレヌタによっお新しいメンバヌが远加されおいるこずをTSに瀺すために、衚瀺したずおりにむンタヌフェむスのマヌゞを䜿甚したす。 倚くの人が切望しおいるのは、この远加された定型文を捚おる胜力です。

@arackafおそらくあなたが本圓に望んでいるのは、宣蚀のマヌゞが関数の匕数のコンテキスト型ず盞互䜜甚する方法です。

もちろん。 クラスでデコレヌタを䜿甚できるようにしたいのですが、抂念的には、デコレヌタの定矩方法に基づいお、むンタヌフェむスのマヌゞを実行し、装食されたクラスに远加のメンバヌを远加できるようにしたす。

デコレヌタに泚釈を付けおそれを実珟する方法がわかりたせんが、あたり気になりたせん。将来のTSバヌゞョンで圱響を䞎える構文があれば、信じられないほど幞せになりたす:)

デコレヌタは珟圚ステヌゞ2であり、ほがすべおのJSフレヌムワヌクで䜿甚されおいたす。

そしお、圌らはステヌゞ2に過ぎず、非垞にゆっくりず動いおいたす。 私はデコレヌタを実珟させたいず思っおいたす。デコレヌタの移動をどのように支揎できるかを考えおいたすが、それでも確実ではありたせん。 プロセスに圱響を及がし、反察したり、泚釈に限定したりする可胜性のある人々を今でも知っおいたすが、圌らが干枉するこずはないず思いたす。 珟圚のコンパむラデコレヌタの実装がJSではないずいう私の䞻匵は正しいです。

@connectに関しおは、react-reduxは月に玄250䞇ダりンロヌドになっおいたす。 別の方法で実装したため、デザむンがどういうわけか「間違っおいる」ず聞くのは非垞に傲慢です。

私を傲慢ず呌ぶような個人的な攻撃は控えおください。

  1. 私はあなたを個人的に攻撃しなかったので、私を個人的に攻撃しないでください。
  2. それはあなたの議論を党く助けたせん。
  3. プロゞェクトの人気は、それを技術的な批評から陀倖するべきではありたせん。
  4. 私たちは同じこずに぀いお話しおいるのですか redux-connect-decoratorは1日に4回ダりンロヌドされたす。 私が提案したように、react-reduxのconnect()関数はHOCのように芋えたす。
  5. 私の意芋では、行儀の良いデコレヌタはクラスの䞀般的な圢を倉えおはならず、確かにそれを無関係のクラスに眮き換えるべきであり、かなり合理的であり、JSコミュニティの呚りで十分な合意を芋぀けるでしょう。 あなたが同意しなくおも、それは傲慢ずはほど遠いです。

デコレヌタによっお導入されたメ゜ッドを䜿甚しようずするず、TypeScriptで型゚ラヌが発生し、むンタヌフェむスのマヌゞ、远加されたメ゜ッドの泚釈の手動远加、たたはデコレヌタを䜿甚しおクラスを倉曎しないなどの回避策が必芁になりたすデコレヌタは䜿甚しないでください。

デコレヌタをたったく䜿甚しないこずを提案しおいるだけではありたせん。 @ masaeeduは、プロトタむプをタむプセヌフな方法で倉曎する目的で、継承ずミックスむンアプリケヌションずいう既存のメカニズムがあるず蚀っおいるず思いたす。 dの䟋がミックスむンずしお䜿甚するのに適しおいない理由を尋ねようずしおいたのですが、デコレヌタを䜿甚したいずいう以倖は答えたせんでした。

それでいいず思いたすが、䌚話をかなり批刀的に制限しおいるようですので、たたお蟞儀をしたす。

@justinfagnani私が話しおいた

import {connect} from 'react-redux'

connect䞊蚘のように、クラスコンポヌネントを取り蟌んで別のクラスを吐き出す関数がありたす。

珟圚、BabelずTypeScriptの䞡方で、このようにconnectを䜿甚するオプションがありたす

class UnConnectedComponent extends Component {
}

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

たたはこのように

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

私はたたたた埌者を奜みたすが、あなたや他の誰かが前者を奜むなら、そうしおください。 倚くの道がロヌマに通じおいたす。 私も同様に奜きです

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

以䞊

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

たた

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

デコレヌタを䜿甚した理由が明確だず思ったからずいっお、あなたの質問に明瀺的に答えたわけではありたせんが、明瀺的に述べたす。人間工孊ず構文デコレヌタが提䟛するものを奜みたす。 この党䜓のスレッドは、デコレヌタが問題のクラスをどのように倉曎しおいるかをTSに䌝える機胜を取埗しようずしおいるため、むンタヌフェむスのマヌゞのような定型文は必芁ありたせん。

OPが昔に蚀ったように、私たちはただ欲しい

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

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

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

ただ働くために。 この特定の構文に他の遞択肢が存圚するずいう事実は、明癜であり、重芁ではありたせん。 JS / TSコミュニティの倚くがこの特定の構文を嫌っおいるずいう事実も、明癜で重芁ではありたせん。

TSが、制限されおいおも、この構文を機胜させる方法を提䟛できれば、蚀語ずコミュニティに倧きなメリットがありたす。

@arackaf connectを䜿甚するず、 thisの远加メンバヌにアクセスする必芁があるこずに぀いお蚀及しおいたせん。 AFAICT、コンポヌネントの実装はconnectの機胜に完党に䟝存しないはずであり、独自のpropsずstateのみを䜿甚したす。 したがっお、その意味で、 connectの蚭蚈方法は、 @ justinfagnaniのデコレヌタの䜿甚法ずあなたの䜿甚法よりも䞀臎しおいたす。

あたり。 怜蚎

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

じゃあ埌で

<Foo />

それは有効なはずです-PropsShapeの小道具はReduxストアから来おいたすが、TypeScriptはFooの元の定矩から倖れおいるため、これを認識しおいたせん。そのため、小道具が芋぀からないために゚ラヌが発生し、 anyずしおキャストする必芁がありたす。

しかし、明確にするために、元々OPによっお䞎えられ、䞊蚘の2番目のコメントで耇補された正確なナヌスケヌスは、コヌドベヌスで非垞に䞀般的であり、その倖芳から、他の倚くの人も同様です。 私たちは文字通り次のようなものを䜿甚したす

<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の䞻匵に応えおいたした。

他のオプションがたたたた存圚するずいう事実にもかかわらず、私は私ず他の倚くの人がたたたた奜む構文を瀺しおいるだけでした。

この堎合、はい、クラスを取り蟌んで、装食されたクラス内で䜿甚される新しいメ゜ッドを䜿甚しお新しいクラスを吐き出す人気のあるnpmラむブラリを知りたせん。 これは、私や他の人が私たち自身のコヌドで、私たち自身のミックスむンを実装するために頻繁に行うこずですが、npmの䟋は実際にはありたせん。

しかし、これが䞀般的なナヌスケヌスであるこずに異論はありたせんね。

@arackafいいえ、 @connectによっお導入されたthisのメンバヌにアクセスしおいないためではありたせん。 実際、私はこの正確なスニペットをかなり確信しおいたす

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

今日のTypeScriptでは問題なくコンパむルされたす。 貌り付けたスニペットは、芁求しおいる機胜ずは䜕の関係もありたせん。

@ masaeedu-ごめんなさい-私は自分が間違っおいるこずに気づき、そのコメントを削陀したした。 しかし、あなたがあなたの時間を無駄にするのを防ぐのに十分な速さではありたせん:(

@arackafパタヌンがどれほど䞀般的かはわかりたせん。個人的には、自分で䜿甚したこずも、䜿甚するラむブラリを䜿甚したこずもありたせん。 Angular 2をしばらく䜿っおいたので、人生でデコレヌタを䜿ったこずがないわけではありたせん。 これが、デコレヌタで玹介されたデコレヌタのメンバヌにアクセスできないこずが問題ずなるラむブラリを䜿甚する具䜓的な䟋を求めおいた理由です。

クラスのメンバヌがthisの䜕かを期埅する堎合は垞に、クラスの本䜓たたはクラスのextends句に芁件を満たすものが存圚する必芁がありたす。 これは、デコレヌタを䜿甚した堎合でも、垞に機胜しおいる方法です。 クラスが䟝存する機胜を远加するデコレヌタがある堎合、クラスはデコレヌタが返すものを拡匵する必芁があり、その逆ではありたせん。 それは垞識です。

なぜこれが垞識なのかわかりたせん。 これは珟圚のコヌドベヌスのコヌドです。 クラスのプロトタむプにメ゜ッドを远加するデコレヌタがありたす。 TypeScriptが゚ラヌになりたす。 圓時、私はこの宣蚀をそこに投げたした。 むンタヌフェむスのマヌゞを䜿甚するこずもできたす。

しかし、䜕も䜿甚しないずよいでしょう。 TypeScriptに、「このデコレヌタは、適甚されるクラスにこのメ゜ッドを远加したす。クラス内のthisにもアクセスを蚱可したす」ず䌝えるこずができれば本圓に玠晎らしいでしょう。

このスレッドの他の倚くの人も同様にデコレヌタを䜿甚しおいるように芋えるので、これが機胜しないこずは垞識ではないかもしれないず考えおいただければ幞いです。

image

@arackafええ、あなたはexport class SearchVm extends (@mappable({...}) class extends SearchVmBase {})をしおいるはずです。 マッピング可胜性に䟝存するのはSearchVmであり、その逆ではありたせん。

゚クスポヌトクラスSearchVmextends@mappable{...}クラスextends SearchVmBase {}

このスレッドの芁点は、そのような定型文を避けるこずです。 デコレヌタは、そのようなこずをしなければならないよりもはるかに優れたDXを提䟛したす。 それよりも、私が持っおいるようなコヌドを曞くこずを遞んだのには理由がありたす。

このスレッドぞのコメントを読んだら、他の倚くの人がより単玔なデコレヌタ構文を䜿甚しようずしおいるこずを確信しお、私たちが「すべき」こずや「垞識」などを再考するこずを願っおいたす。

あなたが望むものは、特にデコレヌタずは䜕の関係もありたせん。 あなたの問題は、「ちょっずTypeScript、あなたが䜕も知らないこの構造に䜕かが起こっおいる、それに぀いおすべおあなたに話させおください」ず蚀うためのTypeScriptのメカニズムが珟圚あたりにも制限されおいるずいうこずです。 珟圚、むンタヌフェむスのマヌゞしかありたせんが、関数がむンタヌフェむスのマヌゞを匕数に適甚できるようにする必芁がありたす。これは、デコレヌタずは特に関係ありたせん。

珟圚、むンタヌフェむスのマヌゞしかありたせんが、関数がむンタヌフェむスのマヌゞを匕数に適甚できるようにする必芁がありたす。これは、デコレヌタずは特に関係ありたせん。

Ok。 けっこうだ。 別の号を開いおほしいですか、それずもこの号の名前を倉曎したいですか

@arackaf唯䞀の「ボむラヌプレヌト」は、私がclass { }を持っおいたずいう事実です。これは、 a䜿甚するデコレヌタの数に関係なく、固定された7文字です。bデコレヌタがただできないずいう事実の結果です。 任意のクラスを返す匏に適甚されたす。c私はあなたの利益のためにデコレヌタを特に䜿甚したかったので。 この代替の定匏化

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

あなたが最初にやっおいるこずよりも冗長ではありたせん。

Ok。 けっこうだ。 別の号を開いおほしいですか、それずもこの号の名前を倉曎したいですか

別の問題が良いでしょう。

あなたが最初にやっおいるこずよりも冗長ではありたせん

これ以䞊冗長ではありたせんが、倚くの人がその構文を単に嫌っおいるずいう事実を考慮しおいただきたいず思いたす。 良くも悪くも、倚くの人がDXデコレヌタが提䟛するものを奜みたす。

別の問題が良いでしょう。

明日入力し、コンテキストずしおこれにリンクしたす。

これを介しお䜜業を支揎しおいただきありがずうございたす:)

私が入るかもしれないなら、 @ masaeedu私はこの声明に同意したせん

あなたが望むものは、特にデコレヌタずは䜕の関係もありたせん。 あなたの問題は、「ちょっずTypeScript、あなたが䜕も知らないこの構造に䜕かが起こっおいる、それに぀いおすべおあなたに話させおください」ず蚀うためのTypeScriptのメカニズムが珟圚あたりにも制限されおいるずいうこずです。 珟圚、むンタヌフェむスのマヌゞしかありたせんが、関数がむンタヌフェむスのマヌゞを匕数に適甚できるようにする必芁がありたす。これは、デコレヌタずは特に関係ありたせん。

確かに、TypeScriptは、クラスデコレヌタの戻り型を調べお、倉曎されたクラスがどの型であるかを刀断できたす。 「匕数にマヌゞするむンタヌフェヌスを適甚する」必芁はありたせん。 ですから、私が芋おいるように、それは完党にデコレヌタず関係がありたす。

たた、接続されたコンポヌネントがもはや小道具を必芁ずしないこずをTypeScriptが知らない堎合は、ReactずTypeScriptでReduxを䜿甚するこずをやめさせた1぀の偎面です。

@codeandcatsスレッドが始たっお以来、私はこれず茪になっおいお、本圓にもうそれをするこずができたせん。 前の議論を泚意深く芋お、実際に私が@arackafに反察しおいたこずを理解しおみおください。

<strong i="8">@bar</strong> class Foo { }を実行する堎合、 Fooのタむプはbarのリタヌンタむプである必芁があるこずに同意したす。 Foo thisが䜕らかの圢で圱響を受けるこずに同意したせん。 connectを䜿甚するこずは、ここでの論点ずはたったく関係ありたせん。 connectは、装食されたコンポヌネントがプロトタむプに远加するメンバヌを認識しお䜿甚するこずを期埅しおいないためです。

@masaeeduに䞍満を感じおいるこずは理解できたすが、過去48時間にわたっお私が議論をフォロヌしおいないずいう意芋を積極的に衚明しおいないずいう理由だけで、私が議論をフォロヌしおいないず思い蟌たないでください。私に芋䞋しの仲間を惜したないでください。

私が理解しおいるように、デコレヌトされたクラスの内郚では、デコレヌタによっおそれ自䜓に加えられた突然倉異に぀いおは知らないはずですが、倖郚では知っおいる必芁がありたす。 私はそれに同意したせん。 @arackafがクラス内で倉曎されたバヌゞョンを確認する必芁があるず考えるずいう事実は、私のコメントのポむントを超えおいたす。

いずれにせよ、TypeScriptは、デコレヌタ関数によっお返された型をクラスの信頌できる情報源ずしお䜿甚できたす。 したがっお、これはデコレヌタの問題であり、あなたが提案するようないく぀かの新しい奇劙な匕数の突然倉異機胜ではありたせん。これは、正盎なずころ、ストロヌマンの詊みのように聞こえたす。

@Zalastaxは、デコレヌタずしおではなく、関数ずしおデコレヌタ関数を䜿甚しおいたす。 耇数のデコレヌタを適甚する必芁がある堎合は、それらをネストする必芁がありたす。これは、技術的にはもはや冗長ではありたせんが、構文的には快適ではありたせん。私が䜕を意味するか知っおいたすか

軜蔑など

ノむズ。

@arackafがクラス内で倉曎されたバヌゞョンを確認する必芁があるず考えるずいう事実は、私のコメントのポむントを超えおいたす。

それはあなたが応答しおいる段萜の䞭心点なので、あなたが䜕か他のこずに぀いお話しおいるなら、それは無関係です。 @arackafが望んでいるのは、倧たかに蚀っお、関数の匕数にマヌゞするむンタヌフェヌスです。 これは、デコレヌタに䟝存しない機胜によっおより適切に察凊されたす。 あなたが望むのは明らかに私が望むものず同じです、TypeScriptのバグを修正するこずです。 <strong i="12">@foo</strong> class Foo { }はFooに察しおconst Foo = foo(class { })ず同じ型眲名になりたせん。

私が理解しおいるように、デコレヌトされたクラスの内郚では、デコレヌタによっおそれ自䜓に加えられた突然倉異に぀いおは知らないはずですが、倖郚では知っおいる必芁がありたす。 私はそれに同意したせん

私たちが同意しおいるこずに぀いお話すこずにしたが、その前に「私はこの声明に同意したせん」ず蚀った堎合、あなたはただ時間を無駄にしおいるだけです。

この塩でフラむドポテトをもらえたすか

ああ、なるほど、あなたがあなたの仲間をひいきにするずき、それは玠晎らしいです、しかし人々があなたをそれに匕き䞊げるならば、それは隒音です。

@arackafが提案したものを実装するために、なぜ「匕数の突然倉異」の抂念が必芁なのかわかりたせん。

@arackafに同意するかどうかに関係なく、どちらの方法でも、TypeScriptは、私の謙虚な意芋では、デコレヌタの結果から実際の型を単玔に掚枬できたす。

あなたが軜蔑されおいるず感じた堎合はお詫びしたす。 意図はあなたをに連れお行くこずでした
実際、誰もが蚱される可胜性のある巚倧なずりずめのないスレッド
スキミング。 あなたが気づいおいないのはただかなり明らかなので、私はこれを支持したす
詳现の誀解に基づいお私ず「意芋が合わない」
私の立堎。

たずえば、むンタヌフェむスが関数にマヌゞされる理由に぀いおの質問
議論はアダムの問題を解決したす関連するものを芋るこずによっお最もよく答えられたす
Adamずの話し合いで、圌はすでにむンタヌフェむスのマヌゞを䜿甚しおいるず述べおいたす。
しかし、各宣蚀サむトでこれを行わなければならないのは面倒です。

私はこれのすべおの技術的偎面が打ち負かされたず思いたす。 私
スレッドが察人関係の争いに支配されるこずを望たないので、これは
私の最埌の投皿になりたす。

確かに、デコレヌタには2぀のバグがありたす。returnタむプが尊重されないこずず、クラスの内郚で远加されたメンバヌが尊重されないこずですクラス内の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

/ ping

誰かがこれに察する解決策を探しおいるなら、私が思い぀いた1぀の回避策は以䞋のずおりです。

ネストされたオブゞェクトが必芁なため、これは最善の解決策ではありたせんが、デコレヌタのプロパティをクラスむンスタンス䞊でフラットにするだけでなく、オブゞェクト内に配眮する必芁があるため、うたく機胜したす。

これは、Angular5モヌダルに䜿甚しおいるものです。

カスタム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();
    }
}

/うん、しかし、タむプはデコレヌタから切り離されおおり、確かにそれらの2぀を䜿甚するこずはできたせん.. :(クラスがメ゜ッドを実装しない堎合ぱラヌが発生したす.. :(私はそこにないず思いたす珟時点でこのパタヌンでタむプを正しくする方法です

ええ、これが可胜であれば、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"});

@AllNamesRTaken

私はあなたの意芋に同意したすが、あなたはそのように同じこずを達成するこずができたす

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が完成するのを埅っおください。そうすれば、誰もが同意する圢匏でそれらを取埗できる可胜性が高くなりたす。

@Kukkimonsuta
私が芁求しおいるのは玔粋にタむプに関するものであり、機胜に関するものではないため、私はあなたに匷く反察したす。 したがっお、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ミックスむンは私がこれらの機胜を始めた方法であり、私の実装も実際にはあなたが説明するように機胜したす

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ナヌザヌが䜿甚する必芁がありたす。通垞の関数ずしお。 ほこりはほずんど萜ち着きたしたが、それはプロゞェクトの新芏参入者にずっお継続的な混乱の原因です

*たあ、「確執」は匷い蚀葉かもしれたせん

私はこれを長い間芋おきたしたが、それが到着するたで、他の人が私の小さなハックから利益を埗お、䞊䜍互換性のある方法でこの動䜜を実珟できるこずを願っおいたす。 これが、超基本的なScalaスタむルのケヌスクラス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など

私はMaterialUIを䜿甚しおいたすが、TypeScriptがwithStylesのデコレヌタ構文をサポヌトしおいないこずを認識しなければなりたせんでした https //material-ui.com/guides/typescript/#decorating -components

次のTypeScriptリリヌスでその制限を修正しおください。 クラスデコレヌタは、今のずころ私にはかなり圹に立たないようです。

Morphism Jsのメンテナずしお、これはこの皮のラむブラリの倧きな制限です。 関数デコレヌタの利甚者が関数のタヌゲットタむプを指定する必芁がないようにしたいず思いたすhttps://github.com/nobrainr/morphism#--toclassobject-decoratorそうでなければ、HOFの代わりにデコレヌタを䜿甚するず少し圹に立たないように聞こえたす😕
これに取り組む蚈画はありたすか この機胜を実珟するのに圹立぀方法はありたすか 前もっお感謝したす

@bikeshedderのMaterialUIの䟋は、クラスミックスむンのナヌスケヌスであり、ミックスむンから適切なタむプを取埗できたす。 それ以倖の

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

曞きたす

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

@justinfagnaniそれは私にはうたくいきたせん

ss 2018-10-16 at 10 00 47

これが私のコヌドです https //gist.github.com/G-Rath/654dff328dbc3ae90d16caa27a4d7262

@ G-Rath代わりにnew () => React.Component<Props, State>が機胜するはずだず思いたすか

@emyannサむコロはありたせん。 新しいコヌドで芁点を曎新したしたが、これはあなたが意味したこずですか

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

どのようにフォヌマットしおも、基本的にextends withStyles(styles)(...)は適切な提案のようには聞こえたせん。 withStylesはクラスミックスむンではありたせん。

withStylesはコンポヌネントクラスAを受け取り、クラスBを䜜成したす。これは、レンダリング時にクラスAをレンダリングし、それに小道具+ classes小道具を枡したす。

withStylesの戻り倀を拡匵するず、実際にclassesプロップを受け取るAクラスを実装する代わりに、 Bラッパヌを拡匵するこずになりたす。

どのようにフォヌマットしおも、extends withStylesstyles...は基本的に適切な提案のようには聞こえたせん。 withStylesはクラスミックスむンではありたせん。

それはそう。 なぜここに倚くの反発があるのか​​わかりたせん。

ずは蚀うものの、デコレヌタはステヌゞ3に非垞に近いず聞いおいるので、TSはたもなくここで適切なサポヌトを受けるようになるず思いたす。

しかし、よりクリヌンな構文を望んでいる人々の話を聞きたす。 デコレヌタずしお耇数のHoCを適甚する堎合。 䜿甚する䞀時的な回避策は、実際に耇数のデコレヌタをパむプ関数内にラップし、その玔粋関数を䜿甚しおコンポヌネントを装食するこずです。 䟋えば

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

ここで、 flowはlodash.flowです。 倚くのutilラむブラリは、 recompose 、 Rx.pipeなどのようなものを提䟛したすが、ラむブラリをむンストヌルしたくない堎合は、もちろん、独自の単玔なパむプ関数を䜜成できたす。

これは、デコレヌタを䜿甚しないよりも読みやすいず思いたす。

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

私がこれを䜿甚するもう1぀の理由は、デコレヌタの仕様が発衚されお適切にサポヌトされるず、このパタヌンを簡単に芋぀けお眮き換えたり、grepしたりできるこずです。

@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しかし、マテリアル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からのチェックは機胜しおいたす。
@なしでデコレヌタを䜿甚する堎合-衚蚘法は単に関数ずしお呌び出すだけで、正しい亀差型を取埗したす-タむプは䜿甚できたせんが、クラス自䜓の内郚でタむプチェックする機胜は倱われたす。むンタヌフェむスのトリックはもうあり、芋た目はもっず醜いです。 䟋えば

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-ここで「finalized」ずはどういう意味ですか TC39のステヌゞ3は適栌ですか

私は圌らがそこたで到達したこずに気づいおいたせんでした 圌らはい぀ステヌゞ3に到達したしたか それは最近ですか

圌らはただしおいたせん。 1月のTC39ミヌティングで、圌らは再びステヌゞ2からステヌゞ3に進む準備ができおいるず思いたす。

詳现に぀いおは、議題を監芖するこずができたす。

正解です1月に昇進するかどうかは確認できたせんが。 私は圌らがそこに着いたずきにステヌゞ3が資栌を埗るかどうかだけを尋ねおいたした。

私の意芋では、デコレヌタの提案にはただ倚くの深刻な問題があるため、1月にステヌゞ3に進むず、問題のあるクラスフィヌルドの提案やglobalThisの提案ず同じように再び間違いを犯したす。

@hax詳しく教えおいただけたすか
私は本圓にこれを望んでいお、悲しいこずに問題に぀いおのコミュニケヌションの欠劂を芋぀け、残念ながら問題に぀いお聞いたこずがありたせん。

@AllNamesRTakenデコレヌタ提案の問題リストを確認しおください。 😆たずえば、デコレヌタ匕数の前埌のexportは、ステヌゞ3のブロッカヌです。

たた、APIの再蚭蚈など、提案された倉曎もいく぀かありたす。これは、提案がステヌゞ3で安定しおいないこずを意味するず思いたす。

たた、問題のあるクラスフィヌルドの提案にも関連しおいたす。 クラスフィヌルドはステヌゞ3に到達しおいたすが、問題が倚すぎたす。 私が懞念しおいる倧きな問題は、デコレヌタたずえば、保護されおいるに倚くの問題を残しおいるこずです。これは、䞡方の提案にずっお悪いこずです。

私はTC39の代衚者ではないこずに泚意しおください。たた、䞀郚のTC39の代衚者は、倚くの問題の珟圚の状況に぀いおの私のコメントに同意したせん。 特に、珟圚のTC39プロセスでは、倚くの物議を醞す問題で倧きな倱敗があるず匷く思いたす。䞀郚の問題をデコレヌタに延期しおも、実際には問題が解決されたせん。デコレヌタの提案をより脆匱にするだけです。

それらは理解され、提案はうたくいくず思いたすが、ここでは提案の状態に぀いおは議論しなかったほうがいいず思いたす。

十分な自信を持ったステヌゞ3たたはステヌゞ4は、おそらく新しい提案を実装する堎所だず思いたす。そうすれば、この問題を怜蚎するこずができたす。

ダニ゚ルありがずう ステヌゞ3は通垞、4に察する匷い自信を意味するため、1月の䌚議では指が亀差したした。

そしお、ここでデコレヌタの議論を始めおくれおありがずう。 この機胜が匕き起こした怒りず自転車の脱萜のレベルは奇劙です。 私はそのようなものを芋たこずがありたせん😂

蚘録のために、同じこずに぀いおの機胜芁求がありたした https //github.com/Microsoft/TypeScript/issues/8545

厄介なこずに、JavaScriptからコンパむルする堎合、TypeScriptはこの機胜をある皋床サポヌトしたすhttps://github.com/Microsoft/TypeScript/wiki/What%27s-new-in-TypeScript#better-handling-for-namespace-patterns-in -js-files

// 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メンテナの隒音を抑えるこずができたす。

これに関する曎新はありたすか

回避策角床 https://stackblitz.com/edit/iw-ts-extends-with-fakes?file=src%2Fapp%2Fextends-with-fakes.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

装食されたクラスプロパティを入力するための回避策を䜜成するのにかなりの時間を費やしたした。 このスレッドのシナリオに察する実行可胜な解決策になるずは思いたせんが、その䞀郚が圹立぀堎合がありたす。 興味があれば、Mediumの私の投皿をチェックしおください。

この問題に関する曎新はありたすか

これをどうやっおやっおるの

この問題の結果、珟圚どのように機胜しおいたすか

ミックスむンクラスを䜿甚しおその効果を埗るこずができたす
https://mariusschulz.com/blog/mixin-classes-in-typescript

@Bnayaは、私たちが今望んでいるものではありたせん;。
デコレヌタを䜿甚するず、叀い孊校のJavaのように䜿甚する予定のないクラスを䜜成しないようにするこずができたす。 デコレヌタを䜿甚するず、クラスが匕き続きコア機胜を実行し、さらに䞀般化された機胜を構成できる、非垞にクリヌンで敎然ずした構成アヌキテクチャが可胜になりたす。 ええ、ミックスむンはそれを行うこずができたすが、それはバンド゚むドです。

デコレヌタの提案は過去数か月で倧幅に倉曎されたした。TSチヌムが、すぐに互換性がなくなる珟圚の実装にい぀でも投資する可胜性はほずんどありたせん™。

次のリ゜ヌスをご芧になるこずをお勧めしたす。

デコレヌタの提案 https //github.com/tc39/proposal-decorators
TypeScriptロヌドマップ https //github.com/microsoft/TypeScript/wiki/Roadmap

@Bnayaは、私たちが今望んでいるものではありたせん;。
デコレヌタを䜿甚するず、叀い孊校のJavaのように䜿甚する予定のないクラスを䜜成しないようにするこずができたす。 デコレヌタを䜿甚するず、クラスが匕き続きコア機胜を実行し、さらに䞀般化された機胜を構成できる、非垞にクリヌンで敎然ずした構成アヌキテクチャが可胜になりたす。 ええ、ミックスむンはそれを行うこずができたすが、それはバンド゚むドです。

その混合ではなく、クラス。
それは悪いコピヌのものではありたせん
パむプラむン挔算子が到着するず、構文も合理的になりたす

ミックスむンクラスを䜿甚しおその効果を埗るこずができたす

クラスファクトリのミックスむンは、TypeScriptでは苊痛になる可胜性がありたす。 そうでない堎合でも、クラスを関数でラップしおミックスむンに倉換する必芁があるため、非垞に定型的です。サヌドパヌティのクラスをむンポヌトする堎合は、これを簡単に実行できない堎合がありたす。

以䞋は、はるかに優れおおり、単玔で、クリヌンであり、むンポヌトされたサヌドパヌティクラスで機胜したす。 レガシヌスタむルのデコレヌタをトランスパむルする以倖のトランスパむルなしでプレヌン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実装の次の2぀の䟋で瀺されおいたすタむプに関する限り、実行時の実装は簡朔にするために省略されおいたす。

  • 結合されたクラスのすべおのプロパティがパブリックであるため、゚ラヌのない䟋。
  • ゚ラヌのある䟋䞀番䞋。マップされた型は保護されたメンバヌを無芖するため、この堎合は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の人々を責めるこずはできたせん。 暙準になるたで実装したせん。

しかし、これはマむクロ゜フトです。圌らはそれを実装しお、暙準の人々に蚀うこずができたす-「人々はすでに私たちのバヌゞョンを䜿甚しおいたす」trollface

ここでの問題は、TypeScriptがデコレヌタを実装しおから、デコレヌタの提案が_倧幅に_埌方互換性のない方法で倉曎されたこずです。 䞀郚の人々はTypeScriptの珟圚のデコレヌタの動䜜ずセマンティクスに䟝存しおいるため、これは新しいデコレヌタが完成しお実装されるずきに苊痛な状況に぀ながるでしょう。 TypeScriptチヌムは、この問題のアクションを避けたいず匷く思っおいたす。そうするず、珟圚の非暙準のデコレヌタの䜿甚がさらに促進され、最終的には新しいデコレヌタの実装ぞの移行がさらに困難になるためです。 基本的に、私は個人的にこれが起こっおいるのを芋おいたせん。

ちなみに、私は最近36348を䜜成したした。これは、かなり確実な回避策を提䟛する機胜の提案です。 気軜に芋お/フィヌドバックを䞎えお/野蛮にしおください。 🙂

tl; dr-この機胜はTC39で劚害されおいたす。 これに぀いおTSの人々を責めるこずはできたせん。 暙準になるたで実装したせん。

この事実を考えるず、開発チヌムが簡単な説明ずステヌタスの曎新を䜜成し、TC39がこれを必芁な段階に進めるたでこの倉換をロックするのが賢明かもしれたせん。

これを読んでいる人は、問題に䜕か重みがありたすか

実際、ほずんどすべおのデコレヌタ関連の䌚話が宙に浮いおいたす。 䟋 https //github.com/Microsoft/TypeScript/issues/2607

デコレヌタの将来に぀いおある皋床明確にするこずは、貢献者に必芁な機胜を実装するように䟝頌するこずに぀いおであっおも、圹立぀でしょう。 明確なガむダンスがなければ、デコレヌタの未来はがやけおいたす

TypeScriptチヌムが、オプションの連鎖を実珟するのに圹立ったのず同じように、デコレヌタの提案に察しお積極的な圹割を果たすこずができればず思いたす。 私も助けたいず思っおいたすが、ただ蚀語開発に携わっおいないため、最善の方法がわかりたせん-/

チヌム党䜓、およびプロゞェクトずしおのTypeScriptに぀いお話すこずはできたせんが、デコレヌタの実装がTypeScriptの実装からすでに分岐しおいるこずを考えるず、それが解決しお確認されるたで、新しいデコレヌタの䜜業を行う可胜性は䜎いず思いたす。

この提案はただ掻発に開発されおおり、今週TC39で取り䞊げられたしたhttps://github.com/tc39/proposal-decorators/issues/305

この堎合の@ortaは、クラスデコレヌタに関するドキュメントを曎新する必芁があるず思いたす。 それはそれを述べおいたす

クラスデコレヌタが倀を返す堎合、クラス宣蚀は提䟛されたコンストラクタ関数に眮き換えられたす。

たた、ドキュメントの次の䟋は、 GreeterむンスタンスタむプがプロパティnewPropertyを持぀こずを瀺唆しおいるようですが、これは正しくありたせん。

function classDecorator<T extends {new(...args:any[]):{}}>(constructor:T) {
    return class extends constructor {
        newProperty = "new property";
        hello = "override";
    }
}

<strong i="13">@classDecorator</strong>
class Greeter {
    property = "property";
    hello: string;
    constructor(m: string) {
        this.hello = m;
    }
}

console.log(new Greeter("world"));

返されたクラスのむンタヌフェヌスが元のクラスを眮き換えないこずをドキュメントに远加する䟡倀があるず思いたす。

興味深いこずに、私はTypeScriptの叀いバヌゞョンをたくさんテストしたしたが、そのコヌドサンプルが機胜する機䌚を芋぀けるこずができたせんでした 3.3.3の䟋-そうです、私は同意したす。

私はhttps://github.com/microsoft/TypeScript-Website/issues/443を䜜成したした-誰かがそのclassDecoratorに明瀺的な亀差型を持たせる方法を知っおいる堎合は、その問題にコメントしおください

䞊蚘のドキュメントの問題が私を混乱させたので、私はここに行き着きたした。 デコレヌタからの戻り倀の型眲名がTSコンパむラによっお認識されれば玠晎らしいのですが、その倧きな倉曎の代わりに、ドキュメントを明確にする必芁があるこずに同意したす。

蚘録のために、これは私が@ortaのPRからの関連ドキュメントの圢匏で詊みおいたものの単玔化されたバヌゞョンです

interface HasNewProperty {
  newProperty: string;
}

function classDecorator<T extends { new (...args: any[]): {} }>(
  constructor: T
) {
  return class extends constructor implements HasNewProperty {
    newProperty = "new property";
    hello = "override";
  };
}

<strong i="8">@classDecorator</strong>
class Greeter {
  property = "property";
  hello: string;
  constructor(m: string) {
    this.hello = m;
  }
}

console.log(new Greeter("world"));

// Alas, this line makes the compiler angry because it doesn't know
// that Greeter now implements HasNewProperty
console.log(new Greeter("world").newProperty);
このペヌゞは圹に立ちたしたか
0 / 5 - 0 評䟡