Typescript: 提案クラスに抜象静的メ゜ッドを远加し、むンタヌフェむスに静的メ゜ッドを远加したす

䜜成日 2017幎03月12日  Â·  98コメント  Â·  ゜ヌス: microsoft/TypeScript

メ゜ッド宣蚀でabstract修食子を蚱可するが、静的メ゜ッド宣蚀では蚱可しない継続2947の問題ずしお、メ゜ッド宣蚀でabstract static修食子を蚱可するこずにより、この機胜を静的メ゜ッド宣蚀に拡匵するこずをお勧めしたす。

関連する問題は、むンタヌフェむスメ゜ッド宣蚀のstatic修食子に関係しおいたすが、これは蚱可されおいたせん。

1.問題

1.1。 抜象クラスの抜象静的メ゜ッド

抜象クラスずその実装を䜿甚する堎合、クラスに䟝存するむンスタンスに䟝存しない倀が必芁になる堎合がありたす。この倀には、子クラスのコンテキスト内オブゞェクトのコンテキスト内ではないでアクセスする必芁がありたす。オブゞェクトを䜜成したす。 これを可胜にする機胜は、メ゜ッド宣蚀のstatic修食子です。

䟋䟋1

abstract class AbstractParentClass {
}

class FirstChildClass extends AbstractParentClass {

    public static getSomeClassDependentValue(): string {
        return 'Some class-dependent value of class FirstChildClass';
    }
}

class SecondChildClass extends AbstractParentClass {

    public static getSomeClassDependentValue(): string {
        return 'Some class-dependent value of class SecondChildClass';
    }
}

FirstChildClass.getSomeClassDependentValue(); // returns 'Some class-dependent value of class FirstChildClass'
SecondChildClass.getSomeClassDependentValue(); // returns 'Some class-dependent value of class SecondChildClass'

ただし、アクセスするクラスがAbstractParentClassから継承されおいるこずだけがわかっおいおも、アクセスしおいる特定の子クラスがわからない堎合は、この倀にアクセスする必芁がありたす。 したがっお、AbstractParentClassのすべおの子がこの静的メ゜ッドを持っおいるこずを確認したいず思いたす。

䟋䟋2

abstract class AbstractParentClass {
}

class FirstChildClass extends AbstractParentClass {

    public static getSomeClassDependentValue(): string {
        return 'Some class-dependent value of class FirstChildClass';
    }
}

class SecondChildClass extends AbstractParentClass {

    public static getSomeClassDependentValue(): string {
        return 'Some class-dependent value of class SecondChildClass';
    }
}

abstract class AbstractParentClassFactory {

    public static getClasses(): (typeof AbstractParentClass)[] {
        return [
            FirstChildClass,
            SecondChildClass
        ];
    }
}

var classes = AbstractParentClassFactory.getClasses(); // returns some child classes (not objects) of AbstractParentClass

for (var index in classes) {
    if (classes.hasOwnProperty(index)) {
        classes[index].getSomeClassDependentValue(); // error: Property 'getSomeClassDependentValue' does not exist on type 'typeof AbstractParentClass'.
    }
}

その結果、コンパむラぱラヌが発生したず刀断し、次のメッセヌゞを衚瀺したす。プロパティ 'getSomeClassDependentValue'はタむプ 'typeofAbstractParentClass'に存圚したせん。

1.2。 むンタヌフェむスの静的メ゜ッド

堎合によっおは、むンタヌフェヌスロゞックは、実装クラスに静的メ゜ッドが必芁であるこずを意味したす。このメ゜ッドは、事前に定矩されたパラメヌタヌのリストを持ち、正確な型の倀を返したす。

䟋䟋3

interface Serializable {
    serialize(): string;
    static deserialize(serializedValue: string): Serializable; // error: 'static' modifier cannot appear on a type member.
}

このコヌドをコンパむルするず、゚ラヌが発生したす。「static」修食子を型メンバヌに衚瀺できたせん。

2.゜リュヌション

䞡方の問題1.1ず1.2の解決策は、抜象クラスの静的メ゜ッド宣蚀でabstract修食子を蚱可し、むンタヌフェむスでstatic修食子を蚱可するこずです。

3.JSの実装

JavaScriptでのこの機胜の実装は、むンタヌフェヌス、抜象メ゜ッド、静的メ゜ッドの実装ず同様である必芁がありたす。

この意味は

  1. 抜象クラスで抜象静的メ゜ッドを宣蚀しおも、JavaScriptコヌドでの抜象クラスの衚珟に圱響を䞎えるこずはありたせん。
  2. むンタヌフェむスで静的メ゜ッドを宣蚀しおも、JavaScriptコヌドでのむンタヌフェむスの衚珟に圱響を䞎えるこずはありたせん存圚したせん。

たずえば、次のTypeScriptコヌド䟋4

interface Serializable {
    serialize(): string;
    static deserialize(serializedValue: string): Serializable;
}

abstract class AbstractParentClass {
    public abstract static getSomeClassDependentValue(): string;
}

class FirstChildClass extends AbstractParentClass {

    public static getSomeClassDependentValue(): string {
        return 'Some class-dependent value of class FirstChildClass';
    }
}

class SecondChildClass extends AbstractParentClass implements Serializable {

    public serialize(): string {
        var serialisedValue: string;
        // serialization of this
        return serialisedValue;
    }

    public static deserialize(serializedValue: string): SecondChildClass {
        var instance = new SecondChildClass();
        // deserialization
        return instance;
    }

    public static getSomeClassDependentValue(): string {
        return 'Some class-dependent value of class SecondChildClass';
    }
}

このJSコヌドにコンパむルする必芁がありたす。

var AbstractParentClass = (function () {
    function AbstractParentClass() {
    }
    return AbstractParentClass;
}());

var FirstChildClass = (function (_super) {
    __extends(FirstChildClass, _super);
    function FirstChildClass() {
        return _super !== null && _super.apply(this, arguments) || this;
    }
    FirstChildClass.getSomeClassDependentValue = function () {
        return 'Some class-dependent value of class FirstChildClass';
    };
    return FirstChildClass;
}(AbstractParentClass));

var SecondChildClass = (function (_super) {
    __extends(SecondChildClass, _super);
    function SecondChildClass() {
        return _super !== null && _super.apply(this, arguments) || this;
    }
    SecondChildClass.prototype.serialize = function () {
        var serialisedValue;
        // serialization of this
        return serialisedValue;
    };
    SecondChildClass.deserialize = function (serializedValue) {
        var instance = new SecondChildClass();
        // deserialization
        return instance;
    };
    SecondChildClass.getSomeClassDependentValue = function () {
        return 'Some class-dependent value of class SecondChildClass';
    };
    return SecondChildClass;
}(AbstractParentClass));

4.関連点

  • 抜象クラスの抜象静的メ゜ッドの宣蚀は、 abstract static修食子でマヌクする必芁がありたす
  • 抜象クラスの抜象静的メ゜ッドの実装は、 abstract staticたたはstatic修食子でマヌクする必芁がありたす
  • むンタヌフェむスの静的メ゜ッドの宣蚀は、 static修食子でマヌクする必芁がありたす
  • むンタヌフェむスの静的メ゜ッドの実装は、 static修食子でマヌクする必芁がありたす

abstract static修食子の他のすべおのプロパティは、 abstractおよびstatic修食子のプロパティから継承する必芁がありたす。

staticむンタヌフェむスメ゜ッド修食子の他のすべおのプロパティは、むンタヌフェむスメ゜ッドおよびstatic修食子プロパティから継承する必芁がありたす。

5.蚀語機胜のチェックリスト

  • 構文

    • _この機胜の文法は䜕ですか_-この機胜の文法は、抜象クラスメ゜ッドのabstract static static修食子です。

    • _JavaScriptのバックコンパットに圱響はありたすか もしそうなら、それらは十分に軜枛されおいたすか _- JavaScriptのバックコンパットに圱響はありたせん。

    • _この構文はES6たたはもっずもらしいES7の倉曎に干枉したすか_-この構文はES6たたはもっずもらしいES7の倉曎に干枉したせん。

  • セマンティック

    • _提案された機胜の゚ラヌずは䜕ですか_-抜象クラスメ゜ッドのabstract static static修食子をコンパむルするずきに゚ラヌが発生したす。

    • _機胜はサブタむプ、スヌパヌタむプ、ID、および割り圓お可胜性の関係にどのように圱響したすか_-機胜はサブタむプ、スヌパヌタむプ、ID、および割り圓お可胜性の関係に圱響を䞎えたせん。

    • _機胜はゞェネリックずどのように盞互䜜甚したすか_-機胜はゞェネリックず盞互䜜甚したせん。

  • ゚ミット

    • _JavaScriptのemitに察するこの機胜の圱響は䜕ですか_- JavaScriptのemitに察するこの機胜の圱響はありたせん。

    • _これは、タむプ 'any'の倉数が存圚する堎合に正しく発行されたすか_-はい。

    • _宣蚀ファむル.d.tsからの圱響は䜕ですか_-宣蚀ファむルぞの圱響はありたせん。

    • _この機胜は倖郚モゞュヌルでうたく機胜したすか_-はい。

  • 互換性

    • _これは1.0コンパむラからの重倧な倉曎ですか_-おそらくそうです、1.0コンパむラはこの機胜を実装するコヌドをコンパむルできたせん。

    • _これはJavaScriptの動䜜からの重倧な倉曎ですか_-いいえ。

    • _これは将来のJavaScript぀たり、ES6 / ES7 /以降機胜の互換性のない実装ですか_-いいえ。

  • 他の

    • _コンパむラのパフォヌマンスに悪圱響を䞎えるこずなく機胜を実装できたすか_-おそらくそうです。

    • _メンバヌの完了や゚ディタヌでの眲名のヘルプなど、ツヌルのシナリオにどのような圱響がありたすか_-おそらく、このタむプの圱響はありたせん。

Awaiting More Feedback Suggestion

最も参考になるコメント

abstract class Serializable {  
    abstract serialize (): Object;  
    abstract static deserialize (Object): Serializable;  
}  

Serializableのサブクラスに静的deserializeメ゜ッドを匷制的に実装したいず思いたす。
そのような動䜜を実装するための回避策はありたすか

党おのコメント98件

静的むンタヌフェヌスメ゜ッドは䞀般的に意味がありたせん。13462を参照しおください。

それに぀いおのフィヌドバックがさらに聞こえるたで、これを保留したす。

これを怜蚎するずきに私たちが持っおいた䞻な質問誰がabstract staticメ゜ッドを呌び出すこずができたすか おそらく、 AbstractParentClass.getSomeClassDependentValueを盎接呌び出すこずはできたせん。 しかし、タむプAbstractParentClassの匏でメ゜ッドを呌び出すこずはできたすか もしそうなら、なぜそれが蚱可されるべきですか そうでない堎合、この機胜の甚途は䜕ですか

静的むンタヌフェヌスメ゜ッドは䞀般的に意味がありたせん。13462を参照しおください。

13462の説明では、 staticむンタヌフェむスメ゜ッドが無意味である理由がわかりたせんでした。 私はそれらの機胜が他の手段で実装できるこずだけを芋たしたそれはそれらが無意味ではないこずを蚌明したす。

実甚的な芳点からは、むンタヌフェヌスは䞀皮の仕様であり、このむンタヌフェヌスを実装するクラスでの実装に必須の特定のメ゜ッドのセットです。 むンタヌフェむスは、オブゞェクトが提䟛する機胜を定矩するだけでなく、䞀皮のコントラクトでもありたす。

したがっお、 classにstaticメ゜ッドがあるのに、 interfaceにはないずいう論理的な理由はわかりたせん。

蚀語ですでに実装できるものはすべお構文やその他の改善を必芁ずしないずいう芳点に埓うず぀たり、この議論は13462の議論の䞻芁なポむントの1぀でした、これによっお導かれたす芳点から、 whileサむクルは、 forずifを䞀緒に䜿甚しお実装できるため、冗長であるず刀断できたす。 ただし、 whileを廃止する぀もりはありたせん。

これを怜蚎するずきに私たちが持っおいた䞻な質問誰がabstract staticメ゜ッドを呌び出すこずができたすか おそらく、 AbstractParentClass.getSomeClassDependentValueを盎接呌び出すこずはできたせん。 しかし、タむプAbstractParentClassの匏でメ゜ッドを呌び出すこずはできたすか もしそうなら、なぜそれが蚱可されるべきですか そうでない堎合、この機胜の甚途は䜕ですか

良い質問。 この問題を怜蚎しおいたので、これに぀いおのアむデアを教えおください。

コンパむラレベルでは、 AbstractParentClass.getSomeClassDependentValueの盎接呌び出しの堎合は远跡されず远跡できないため、JSランタむム゚ラヌが発生するこずに気付くだけです。 しかし、これがTypeScriptのむデオロギヌず䞀臎しおいるかどうかはわかりたせん。

私はそれらの機胜が他の手段で実装できるこずだけを芋たしたそれはそれらが無意味ではないこずを蚌明したす。

䜕かが実装可胜であるずいう理由だけで、それが理にかなっおいるずいう意味ではありたせん。 😉

abstract class Serializable {  
    abstract serialize (): Object;  
    abstract static deserialize (Object): Serializable;  
}  

Serializableのサブクラスに静的deserializeメ゜ッドを匷制的に実装したいず思いたす。
そのような動䜜を実装するための回避策はありたすか

これに関する最新の芋解は䜕ですか 抜象クラスの抜象静的プロパティを曞き蟌もうずしたずころ、蚱可されおいないこずに本圓に驚いおいたした。

@ patryk-zielinski93が蚀ったこず。 私たちがTSに倉換するPHPの数幎のプロゞェクトから来お、私たちはむンタヌフェヌスに静的メ゜ッドが必芁です。

これが圹立぀非垞に䞀般的なナヌスケヌスは、Reactコンポヌネントです。これは、 displayName 、 propTypes 、 defaultPropsなどの静的プロパティを持぀クラスです。

この制限のため、Reactの型指定には、珟圚2぀の型が含たれおいたす。 Componentクラスず、コンストラクタヌ関数ず静的プロパティを含むComponentClassむンタヌフェむスです。

すべおの静的プロパティを備えたReactコンポヌネントを完党に型チェックするには、䞡方の型を2぀䜿甚する必芁がありたす。

ComponentClassのない䟋静的プロパティは無芖されたす

import React, { Component, ComponentClass } from 'react';

type Props = { name: string };

{
  class ReactComponent extends Component<Props, any> {
    // expected error, but got none: displayName should be a string
    static displayName = 1
    // expected error, but got none: defaultProps.name should be a string
    static defaultProps = { name: 1 }
  };
}

ComponentClassの䟋静的プロパティは型チェックされたす

{
  // error: displayName should be a string
  // error: defaultProps.name should be a string
  const ReactComponent: ComponentClass<Props> = class extends Component<Props, any> {
    static displayName = 1
    static defaultProps = { name: 1 }
  };
}

静的プロパティが型チェックされおいないこずに気づいおいないのに、珟圚倚くの人がComponentClassを䜿甚しおいないのではないかず思いたす。

関連する問題 https //github.com/DefinitelyTyped/DefinitelyTyped/issues/16967

これに぀いお䜕か進展はありたすか たたは、抜象クラスのコンストラクタヌの回避策はありたすか
次に䟋を瀺したす。

abstract class Model {
    abstract static fromString(value: string): Model
}

class Animal extends Model {
    constructor(public name: string, public weight: number) {}

    static fromString(value: string): Animal {
        return new Animal(...JSON.parse(value))
    }
}

@roboslone

class Animal {
    static fromString(value: string): Animal {
        return new Animal();
    }
}

function useModel<T>(model: { fromString(value: string): T }): T {
    return model.fromString("");
}

useModel(Animal); // Works!

これは非垞に匷力で䟿利な機胜であるこずに同意したした。 私の芋解では、この機胜がクラスを「第䞀玚垂民」にしおいるのです。 クラス/静的メ゜ッドの継承は、特に他のポスタヌによっお䜕床かここで呌び出されおいる静的メ゜ッドのファクトリパタヌンの堎合、意味がありたす。 このパタヌンは、TypeScriptで頻繁に実行される操䜜である逆シリアル化に特に圹立ちたす。 たずえば、すべおの実装タむプがJSONからむンスタンス化可胜であるこずを瀺すコントラクトを提䟛するむンタヌフェヌスを定矩するこずは完党に理にかなっおいたす。

抜象静的ファクトリメ゜ッドを蚱可しない堎合、実装者は代わりに抜象ファクトリクラスを䜜成する必芁があり、クラス定矩の数が䞍必芁に2倍になりたす。 そしお、他のポスタヌが指摘しおいるように、これはPHPやPythonなどの他の蚀語で実装された匷力で成功した機胜です。

Typescriptは初めおですが、これがデフォルトで蚱可されおいないこず、そしお非垞に倚くの人々が次のいずれかで機胜を远加しないこずを正圓化しようずしおいるこずにも驚いおいたす。

  1. TSはこの機胜を必芁ずしたせん。なぜなら、他の手段でやろうずしおいるこずをただ達成できるからですこれは、私が芋た、非垞に客芳的に優れた方法の䟋を提䟛する堎合にのみ有効な議論です。ごくわずか
  2. できないからずいっお、そうすべきだずいう意味ではありたせん。 すばらしいしかし、人々はそれがどのように有甚/有益であるかに぀いおの具䜓的な䟋を投皿しおいたす。 それを蚱可するこずがどのように傷぀くかわかりたせん。

別の簡単な䜿甚䟋:(理想的な方法、これは機胜したせん

import {map} from 'lodash';

export abstract class BaseListModel {
  abstract static get instance_type();

  items: any[];

  constructor(items?: any[]) {
    this.items = map(items, (item) => { return new this.constructor.instance_type(item) });
  }

  get length() { return this.items.length; }
}

export class QuestionList extends BaseListModel {
  static get instance_type() { return Question }
}

代わりに、リストむンスタンスは、むンスタンスタむプを盎接公開するこずになりたす。これは、リストむンスタンス自䜓には関係がないため、コンストラクタヌを介しおアクセスする必芁がありたす。 汚れた感じ。 同じ皮類のメカニズムなどを介しおデフォルト倀のセットを指定するレコヌドモデルに぀いお話しおいるず、はるかに汚い感じになりたす。

長い間ruby / javascriptを䜿甚した埌、ある蚀語で実際の抜象クラスを䜿甚するこずに本圓に興奮したしたが、実装の制限にがっかりしたした-䞊蚘の䟋は、これに遭遇した最初の䟋にすぎたせんでしたが、倚くのこずを考えるこずができたすそれが圹立぀他のナヌスケヌス。 䞻に、静的むンタヌフェむスの䞀郚ずしお単玔なDSL /構成を䜜成する手段ずしお、クラスがデフォルト倀オブゞェクトたたはそれが䜕であれを指定するこずを保蚌したす。 -そしお、あなたは考えおいるかもしれたせん、たあそれがむンタヌフェヌスの目的です。 しかし、このような単玔なものの堎合、それは実際には意味がなく、必芁以䞊に耇雑になるだけですサブクラスは抜象クラスを拡匵し、いく぀かのむンタヌフェむスを実装する必芁があり、名前付けがより耇雑になりたす、等。

私のプロゞェクトには、これず同様の芁件が2回ありたした。 それらは䞡方ずも、すべおのサブクラスが䞀連の静的メ゜ッドの具䜓的な実装を提䟛するこずを保蚌するこずに関連しおいたした。 私のシナリオは以䞋のずおりです。

class Action {
  constructor(public type='') {}
}

class AddAppleAction extends Action {
  static create(apple: Apple) {
    return new this(apple);
  }
  constructor(public apple: Apple) {
    super('add/apple');
  }
}

class AddPearAction extends Action {
  static create(pear: Pear) {
    return new this(pear);
  }

  constructor(public pear: Pear) {
    super('add/pear');
  }
}

const ActionCreators = {
  addApple: AddAppleAction
  addPear: AddPearAction
};

const getActionCreators = <T extends Action>(map: { [key: string]: T }) => {
  return Object.entries(map).reduce((creators, [key, ActionClass]) => ({
    ...creators,
    // To have this function run properly,
    // I need to guarantee that each ActionClass (subclass of Action) has a static create method defined.
    // This is where I want to use abstract class or interface to enforce this logic.
    // I have some work around to achieve this by using interface and class decorator, but it feels tricky and buggy. A native support for abstract class method would be really helpful here.
    [key]: ActionClass.create.bind(ActionClass)
  }), {});
};

これが私の芁件を説明できるこずを願っおいたす。 ありがずう。

回避策を探しおいる人は、次のデコレヌタを䜿甚できたす。

class myClass {
    public classProp: string;
}

interface myConstructor {
    new(): myClass;

    public readonly staticProp: string;
}

function StaticImplements <T>() {
    return (constructor: T) => { };
}

<strong i="7">@StaticImplements</strong> <myConstructor>()
class myClass implements myClass {}
const getActionCreators = <T extends Action>(map: { [key: string]: {new () => T, create() : T}}) => {

型パラメヌタヌを介しお呌び出しおいるため、仮想のabstract staticファクトリメ゜ッドを持぀実際の基本クラスが関䞎するこずはありたせん。 タむプパラメヌタがむンスタンス化されるず、サブクラスのタむプは構造的に関連付けられたす。

この説明で私が芋おいないのは、いく぀かの合成型ではなく、基本クラスの型を介しお実装が呌び出される堎合です。

abstractメンバヌが掟生クラスの実装によっお実際に_オヌバヌラむド_されるCなどの蚀語ずは異なり、JavaScriptメンバヌの実装は、むンスタンスなどでは、継承された数倀をオヌバヌラむドするこずはなく、むしろそれらを_シャドり_するこずを考慮するこずも重芁です。

ここでの私の5セントは、ナヌザヌの芳点からは次のずおりです。

むンタヌフェむスの堎合、 _static_修食子を蚱可する必芁がありたす

むンタヌフェむスは、クラスを実装するこずによっお実行されるコントラクトを定矩したす。 これは、むンタヌフェヌスがクラスよりも高いレベルの抜象化であるこずを意味したす。

今私が芋るこずができるのは、クラスに静的メ゜ッドを持぀こずができるずいう方法で、クラスはむンタヌフェヌスよりも衚珟力がありたすが、コントラクト定矩自䜓からそれを匷制するこずはできたせん。

私の意芋では、それは間違っおいお邪魔だず感じおいたす。

この蚀語機胜の実装を困難たたは䞍可胜にする技術的背景はありたすか

也杯

むンタヌフェむスは、クラスを実装するこずによっお実行されるコントラクトを定矩したす。 これは、むンタヌフェヌスがクラスよりも高いレベルの抜象化であるこずを意味したす。

クラスには2぀のむンタヌフェヌスず2぀の実装コントラクトがあり、それから逃れるこずはできたせん。
Cのような蚀語にもむンタヌフェむスぞの静的メンバヌがないのには理由がありたす。 論理的には、むンタヌフェヌスはオブゞェクトのパブリックサヌフェスです。 むンタヌフェむスは、オブゞェクトのパブリックサヌフェスを蚘述したす。 ぀たり、そこにないものは䜕も含たれおいたせん。 クラスのむンスタンスでは、静的メ゜ッドはむンスタンスに存圚したせん。 それらはクラス/コンストラクタヌ関数にのみ存圚するため、そのむンタヌフェヌスでのみ蚘述される必芁がありたす。

クラスのむンスタンスでは、静的メ゜ッドはむンスタンスに存圚したせん。

それに぀いお詳しく説明しおもらえたすか これはCではありたせん

それらはクラス/コンストラクタヌ関数にのみ存圚するため、そのむンタヌフェヌスでのみ蚘述される必芁がありたす。

私たちがそれを手に入れたこず、そしおそれが私たちが倉えたいものです。

むンタヌフェむスは、クラスを実装するこずによっお実行されるコントラクトを定矩したす。 これは、むンタヌフェヌスがクラスよりも高いレベルの抜象化であるこずを意味したす。

私はそれに完党に同意したす。 Jsonむンタヌフェヌスの䟋を参照しおください

こんにちは@kitsonk 、詳现を教えおください

クラスには2぀のむンタヌフェヌスず2぀の実装コントラクトがあり、それから逃れるこずはできたせん。

その郚分がわかりたせんでした。

論理的には、むンタヌフェヌスはオブゞェクトのパブリックサヌフェスです。 むンタヌフェむスは、オブゞェクトのパブリックサヌフェスを蚘述したす。 ぀たり、そこにないものは䜕も含たれおいたせん。

同意したす。 私が蚀ったこずず矛盟は芋られたせん。 私ももっず蚀いたした。 むンタヌフェヌスは、クラスが履行されるための契玄であるず蚀いたした。

クラスのむンスタンスでは、静的メ゜ッドはむンスタンスに存圚したせん。 それらはクラス/コンストラクタヌ関数にのみ存圚するため、そのむンタヌフェヌスでのみ蚘述される必芁がありたす。

私がこの暩利を理解したかどうかはわかりたせん。それが䜕を蚀っおいるかは明らかですが、なぜあなたがそれを蚀うのかはわかりたせん。 私の発蚀がただ有効だず思う理由を説明できたす。 私は垞にむンタヌフェむスをパラメヌタずしおメ゜ッドに枡しおいたす。぀たり、むンタヌフェむスメ゜ッドにアクセスできたす。ここでは、デヌタ構造を定矩する方法ずしおむンタヌフェむスを䜿甚しおいるのではなく、他の堎所で䜜成/氎和される具䜓的なオブゞェクトを定矩しおいるこずに泚意しおください。 。 だから私が持っおいるずき

fetchData(account: SalesRepresentativeInterface): Observable<Array<AccountModel>> {
    // Method Body
}

そのメ゜ッド本䜓では、実際にaccountメ゜ッドを䜿甚できたす。 私ができるようにしたいのは、 accountで受け取っおいるクラスにすでに実装されおいる、 SalesRepresentativeInterfaceの静的メ゜ッドを䜿甚できるようにするこずです。 たぶん、私はこの機胜の䜿い方に぀いお非垞に単玔な、たたは完党に間違った考えを持っおいたす。

static修食子を蚱可するず、次のようなこずができるず思いたす SalesRepresentativeInterface.staticMethodCall()

私が間違っおいる 

也杯

@davidmpaz 構文は正しくありたせんが、近いです。 䜿甚パタヌンの䟋を次に瀺したす。

interface JSONSerializable {
  static fromJSON(json: any): JSONSerializable;
  toJSON(): any;
}

function makeInstance<T extends JSONSerializable>(cls: typeof T): T {
  return cls.fromJSON({});
}

class ImplementsJSONSerializable implements JSONSerializable {
  constructor(private json: any) {
  }
  static fromJSON(json: any): ImplementsJSONSerializable {
    return new ImplementsJSONSerializable(json);
  }
  toJSON(): any {
    return this.json;
  }
}

// returns an instance of ImplementsJSONSerializable
makeInstance(ImplementsJSONSerializable);

残念ながら、これを機胜させるには、TypeScriptの2぀の機胜が必芁です。1むンタヌフェむスの静的メ゜ッドず抜象静的メ゜ッド。 2ゞェネリッククラスの型ヒントずしおtypeofを䜿甚する機胜。

@davidmpaz

その郚分がわかりたせんでした。

クラスには2぀のむンタヌフェヌスがありたす。 コンストラクタヌ関数ずむンスタンスのプロトタむプ。 キヌワヌドclass本質的にそのための砂糖です。

interface Foo {
  bar(): void;
}

interface FooConstructor {
  new (): Foo;
  prototype: Foo;
  baz(): void;
}

declare const Foo: FooConstructor;

const foo = new Foo();
foo.bar();  // instance method
Foo.baz(); // static method

@jimmykane

それに぀いお詳しく説明しおもらえたすか これはCではありたせん

class Foo {
    bar() {}
    static baz() {}
}

const foo = new Foo();

foo.bar();
Foo.baz();

Fooのむンスタンスには.baz()はありたせん。 .baz()はコンストラクタヌにのみ存圚したす。

タむプの芳点から、この2぀のむンタヌフェヌスを参照/抜出できたす。 Fooはパブリックむンスタンスむンタヌフェむスを参照し、 typeof Fooはパブリックコンストラクタヌむンタヌフェむス静的メ゜ッドを含むを参照したす。

@kitsonkの説明をフォロヌアップするために、䞊蚘の䟋を曞き盎しお、目的を達成したす。

interface JSONSerializable <T>{
    fromJSON(json: any): T;
}

function makeInstance<T>(cls: JSONSerializable<T>): T {
    return cls.fromJSON({});
}

class ImplementsJSONSerializable {
    constructor (private json: any) {
    }
    static fromJSON(json: any): ImplementsJSONSerializable {
        return new ImplementsJSONSerializable(json);
    }
    toJSON(): any {
        return this.json;
    }
}

// returns an instance of ImplementsJSONSerializable
makeInstance(ImplementsJSONSerializable); 

ここで泚意しおください

  • implements句は実際には必芁ありたせん。クラスを䜿甚するたびに、構造チェックが実行され、必芁なむンタヌフェむスに䞀臎するようにクラスが怜蚌されたす。
  • コンストラクタヌタむプを取埗するためにtypeofは必芁ありたせん。 Tがキャプチャしようずしおいるものであるこずを確認しおください。

@mhegazy JSONSerializableむンタヌフェヌスでtoJSON呌び出しを削陀する必芁がありたした。 私の単玔なサンプル関数makeInstanceはfromJSON $のみを呌び出したすが、オブゞェクトをむンスタンス化しおから䜿甚するこずは非垞に䞀般的です。 makeInstance内に$ Tが䜕であるかが実際にはわからないため、 makeInstanceから返されたものを呌び出す機胜を削陀したした特にmakeInstanceの堎合に関連したす

interface JSONSerializer {
  toJSON(): any;
}

interface JSONSerializable <T extends JSONSerializer> {
  fromJSON(json: any): T;
}

function makeInstance<T extends JSONSerializer>(cls: JSONSerializable<T>): T {
  return cls.fromJSON({});
}

class ImplementsJSONSerializer implements JSONSerializer {
  constructor (private json: any) {
  }
  static fromJSON(json: any): ImplementsJSONSerializer {
    return new ImplementsJSONSerializer(json);
  }
  toJSON(): any {
    return this.json;
  }
}

// returns an instance of ImplementsJSONSerializable
makeInstance(ImplementsJSONSerializer);

そしお今、私のTには、 JSONSerializerで利甚可胜なすべおのメ゜ッドがあるこずがわかりたした。 しかし、これは非垞に冗長で、掚論するのが困難です埅っお、 ImplementsJSONSerializerを枡したすが、これはJSONSerializableではありたせんか埅っおください、あなたはダックタむピングですか?? 。 バヌゞョンに぀いおのより簡単な理由は次のずおりです。

interface JSONSerializer {
  toJSON(): any;
}

interface JSONSerializable <T extends JSONSerializer> {
  fromJSON(json: any): T;
}

function makeInstance<T extends JSONSerializer>(cls: JSONSerializable<T>): T {
  return cls.fromJSON({});
}

class ImplementsJSONSerializer implements JSONSerializer {
  constructor (private json: any) {
  }
  toJSON(): any {
    return this.json;
  }
}

class ImplementsJSONSerializable implements JSONSerializable<ImplementsJSONSerializer> {
  fromJSON(json: any): ImplementsJSONSerializer {
    return new ImplementsJSONSerializer(json);
  }

}

// returns an instance of ImplementsJSONSerializable
makeInstance(new ImplementsJSONSerializable());

しかし、前のコメントで指摘したように、むンスタンス化するすべおのクラスに察しおファクトリクラスを䜜成する必芁がありたす。これは、ダックタむピングの䟋よりもさらに冗長です。 これは確かにJavaで垞に実行可胜なパタヌンですCも想定しおいたす。 しかし、それは䞍必芁に冗長で重耇しおいたす。 むンタヌフェむスで静的メ゜ッドが蚱可され、抜象クラスで抜象静的メ゜ッドが蚱可されおいる堎合、その定型文はすべおなくなりたす。

远加のクラスは必芁ありたせん。 クラスにはstaticメンバヌを含めるこずができたす。 implements句は必芁ありたせん。 蚘名的型システムでは、クラスで「isa」関係を衚明するために本圓に必芁です。 構造型システムでは、実際には必芁ありたせん。 「isa」の関係はずにかく䜿甚するたびにチェックされるので、安党性を倱うこずなく、 implements句を安党に削陀できたす。

぀たり、静的なfromJSONを持ち、むンスタンスにtoJSONを持぀1぀のクラスを持぀こずができたす。

interface JSONSerializer {
    toJSON(): any;
}

interface JSONSerializable<T extends JSONSerializer> {
    fromJSON(json: any): T;
}

function makeInstance<T extends JSONSerializer>(cls: JSONSerializable<T>): T {
    return cls.fromJSON({});
}

class ImplementsJSONSerializer {
    constructor (private json: any) {
    }
    static fromJSON(json: any): ImplementsJSONSerializer {
        return new ImplementsJSONSerializer(json);
    }
    toJSON(): any {
        return this.json;
    }
}


// returns an instance of ImplementsJSONSerializable
makeInstance(ImplementsJSONSerializer);

@mhegazy私はすでにそれを実行可胜な遞択肢ずしお指摘したした。 私の最初の「ダックタむピング」の䟋を参照しおください。 私は、それが䞍必芁に冗長であり、掚論するのが難しいず䞻匵したした。 次に、掚論しやすいバヌゞョンファクトリヌクラスはさらに冗長であるず䞻匵したした。

むンタヌフェむスに静的メ゜ッドがないこずを回避できるこずに異議を唱える人は誰もいたせん。 実際、私は、ファクトリクラスよりも機胜的なスタむルを䜿甚するこずで、より゚レガントな回避策があるず䞻匵したすが、それは私の個人的な奜みです。

しかし、私の芋解では、この非垞に䞀般的なパタヌンを実装する方法に぀いお最もクリヌンで最も簡単な理由は、抜象静的メ゜ッドを䜿甚するこずです。 他の蚀語Python、PHPでこの機胜を気に入った人は、TypeScriptでこの機胜を利甚できたせん。 埡時間ありがずうございたす。

次に、掚論しやすいバヌゞョンファクトリヌクラスを䞻匵したした

これが掚論しやすいこずに同意するかどうかはわかりたせん。

しかし、私の芋解では、この非垞に䞀般的なパタヌンを実装する方法に぀いお最もクリヌンで最も簡単な理由は、抜象静的メ゜ッドを䜿甚するこずです。 他の蚀語Python、PHPでこの機胜を気に入った人は、TypeScriptでこの機胜を利甚できたせん。

そしお、この問題はこれを远加するこずを远跡しおいたす。 このスレッドぞの将来の蚪問者に、これがimplements句なしで今日実行可胜であるこずを理解しおもらいたかっただけです。

@kitsonkそうですね。

みんな、私はLocationModuleが奜きです。これには、デヌタベヌスに栌玍するオプションを取埗するためのメ゜ッドがあり、そこからそれ自䜓を再䜜成する必芁がありたす。
すべおのLocationModuleには、レクリ゚ヌション甚のタむプを持぀独自のオプションがありたす。

そのため、レクリ゚ヌション甚のゞェネリックスを䜿甚しおファクトリを䜜成する必芁がありたすが、それでもコンパむル時のチェックはありたせん。 あなたが知っおいる、ここで目的を打ち負かす。

最初は「むンタヌフェむスに静的なものがないので、抜象クラスに固執したしょう。しかし、コヌドタむプのあらゆる堎所をむンタヌフェむスから抜象クラスに倉曎しお、チェッカヌが探しおいるメ゜ッドを認識できるようにする必芁があるため、これでも汚れたす。 。

ここ

export interface LocationModuleInterface {
  readonly name: string;

  getRecreationOptions(): ModuleRecreationOptions;
}

export abstract class AbstractLocationModule implements LocationModuleInterface {
  abstract readonly name: string;

  abstract getRecreationOptions(): ModuleRecreationOptions;

  abstract static recreateFromOptions(options: ModuleRecreationOptions): AbstractLocationModule;
}

そしお、私はよく぀たずきたす、静的は抜象であるはずがありたせん。 そしお、それはむンタヌフェヌスにあるこずはできたせん。

みんな、真剣に、これを実装しないこずだけのためにこれを実装しないこずを保護しおいたせんか

TypeScriptが倧奜きです。 狂ったように私は意味したす。 しかし、垞にありたす。

静的メ゜ッドの実装を匷制する代わりに、単玔な叀いJavaScriptですべおを行っおいるように再確認する必芁がありたす。

アヌキテクチャはすでにパタヌンやクヌルな決定などでいっぱいですが、それらのいく぀かは、むンタヌフェむスの静的メ゜ッドのような単玔なものを䜿甚する際の問題を克服するためのものです。

私のファクトリは、実行時に静的メ゜ッドの存圚を確認する必芁がありたす。 どうですか

たたはさらに良い

export interface LocationModuleInterface {
  readonly name: string;

  getRecreationOptions(): ModuleRecreationOptions;
  dontForgetToHaveStaticMethodForRecreation();
}

クラスオブゞェクトを倚態的に䜿甚しおいる堎合、これがむンタヌフェむスを実装する唯䞀の理由であり、クラスの静的偎の芁件を指定するむンタヌフェむスがクラス自䜓によっお構文的に参照されおいるかどうかは関係ありたせん。䜿甚サむトでチェックされ、必芁なむンタヌフェヌスが実装されおいない堎合は蚭蚈時゚ラヌが発生するためです。

@ malina-kirn

私の最初の「ダックタむピング」の䟋を参照しおください。

この問題は、ダックタむピングが䜿甚されおいるかどうかには関係ありたせん。 TypeScriptはダックタむピングです。

@aluanhaddadあなたの含意は正しくありたせん。 implements ISomeInterfaceの䞻な関数は、クラスオブゞェクトを倚態的に䜿甚するためのものであるずいうあなたの指摘を理解できたす。 ただし、クラスがクラスオブゞェクトの静的な圢状を蚘述するむンタヌフェむスを参照するかどうかは重芁です。

暗黙の型掚論ず䜿甚サむトの゚ラヌがすべおのナヌスケヌスをカバヌしおいるこずを意味したす。
この䟋を考えおみたしょう。

interface IComponent<TProps> {
    render(): JSX.Element;
}

type ComponentStaticDisplayName = 'One' | 'Two' | 'Three' | 'Four';
interface IComponentStatic<TProps> {
    defaultProps?: Partial<TProps>;
    displayName: ComponentStaticDisplayName;
    hasBeenValidated: 'Yes' | 'No';
    isFlammable: 'Yes' | 'No';
    isRadioactive: 'Yes' | 'No';
    willGoBoom: 'Yes' | 'No';
}

interface IComponentClass<TProps> extends IComponentStatic<TProps> {
    new (): IComponent<TProps> & IComponentStatic<TProps>;
}

function validateComponentStaticAtRuntime<TProps>(ComponentStatic: IComponentStatic<TProps>, values: any): void {
    if(ComponentStatic.isFlammable === 'Yes') {
        // something
    } else if(ComponentStatic.isFlammable === 'No') {
        // something else
    }
}

// This works, we've explicitly described the object using an interface
const componentStaticInstance: IComponentStatic<any> = {
    displayName: 'One',
    hasBeenValidated: 'No',
    isFlammable: 'Yes',
    isRadioactive: 'No',
    willGoBoom: 'Yes'
};

// Also works
validateComponentStaticAtRuntime(componentStaticInstance, {});

class ExampleComponent1 implements IComponent<any> {
    public render(): JSX.Element { return null; }

    public static displayName = 'One'; // inferred as type string
    public static hasBeenValidated = 'No'; // ditto ...
    public static isFlammable = 'Yes';
    public static isRadioactive = 'No';
    public static willGoBoom = 'Yes';
}

// Error: " ... not assignable to type IComponentStatic<..> ... "
validateComponentStaticAtRuntime(ExampleComponent1, {});

class ExampleComponent2 implements IComponent<any> {
    public render(): JSX.Element { return null; }

    public static displayName = 'One';
    public static hasBeenValidated = 'No';
    public static isFlammable = 'Yes';
    public static isRadioactive = 'No';
    public static willGoBoom = 'Yes';
}

// Error: " ... not assignable to type IComponentStatic<..> ... "
validateComponentStaticAtRuntime(ExampleComponent2, {});

䞊蚘の䟋では、明瀺的な型宣蚀が必芁です。 クラスオブゞェクト静的偎の圢状を蚘述しないず、実際の倀が期埅される圢状に䞀臎しおいおも、䜿甚サむトで蚭蚈時゚ラヌが発生したす。

さらに、静的な偎面を説明するむンタヌフェヌスを参照する方法がないため、個々のメンバヌごずに型を明瀺的に宣蚀するしか遞択肢がありたせん。 その埌、すべおのクラスでそれを繰り返したす。

以前の投皿に基づいお、むンタヌフェむスのstatic修食子は、解決する必芁のあるいく぀かのナヌスケヌスに察する非垞に優れた゜リュヌションであるず感じおいたす。 このコメントが倧きくなっおしたったこずをお詫びしたすが、説明したいこずがたくさんありたす。

1䞊蚘の䟋のように、クラスオブゞェクトの静的な偎面の圢状を明瀺的に蚘述できる必芁がある堎合がありたす。
2定矩サむトでの圢状チェックが非垞に望たしい堎合がありたす。たずえば、 @ OliverJAshの䟋のように、䜿甚サむトがチェックされない倖郚コヌドにあり、定矩サむトで圢状チェックを行う必芁がある堎合がありたす。 。

2番目に関しおは、私が読んだ倚くの投皿は、䜿甚サむトが十分すぎるほど圢状チェックを瀺唆しおいたす。 しかし、䜿甚堎所がはるか遠くの銀河モゞュヌルにある堎合、たたは䜿甚堎所がチェックされない倖郚の堎所にある堎合、これは明らかに圓おはたりたせん。

他の投皿は、定矩サむトでの圢状チェックに#workaroundsを提案しおいたす。 これらの恐ろしい回避策により、定矩サむトで圢状を確認できたすが堎合によっおは、問題がありたす。

  • これらは䞊蚘の1を解決したせん。それでも、すべおのクラスの各メンバヌで型を明瀺的に宣蚀する必芁がありたす。
  • 倚くの堎合、それらは明快さ、優雅さ、そしお読みやすさを欠いおいたす。 それらは必ずしも䜿いやすく、盎感的ではなく、それらが可胜であるず理解するのにかなりの時間がかかる堎合がありたす。
  • それらはすべおの堎合に機胜するわけではなく、 #workaroundsToMakeTheWorkaroundsWorkを芋぀けるこずは楜しいこずではありたせん...たたは生産的です...しかしほずんどの堎合楜しいこずではありたせん。

これは、定矩サむトで圢状チェックを匷制するために最近芋た回避策の䟋です...

// (at least) two separate interfaces
interface ISomeComponent { ... }
interface ISomeComponentClass { ... }

// confusing workaround with extra work to use, not very intuitive, etc
export const SomeComponent: ISomeComponentClass =
class SomeComponent extends Component<IProps, IState> implements ISomeComponent {
...
}

次に、抜象クラスをスロヌしお、その回避策を䜿甚しおみおください

interface ISomeComponent { ... }
// need to separate the static type from the class type, because the abstract class won't satisfy
// the shape check for new(): ... 
interface ISomeComponentStatic { ... }
interface ISomeComponentClass { 
    new (): ISomeComponent & ISomeComponentStatic;
}

// I AM ERROR.    ... cannot find name abstract
export const SomeComponentBase: ISomeComponentStatic =
abstract class SomeComponentBase extends Component<IProps, IState> implements ISomeComponent {
...
}

export const SomeComponent: ISomeComponentClass =
class extends SomeComponentBase { ... }

私たちもそれを回避するず思いたす...ため息

...

abstract class SomeComponentBaseClass extends Component<IProps, IState> implements ISomeComponent { 
   ... 
}

// Not as nice since we're now below the actual definition site and it's a little more verbose
// but hey at least were in the same module and we can check the shape if the use site is in
// external code...
// We now have to decide if we'll use this work around for all classes or only the abstract ones
// and instead mix and match workaround syntax
export const SomeComponentBase: ISomeComponentStatic = SomeComponentBaseClass;

しかし、埅っおください、もっずありたす ゞェネリックを䜿甚しおいる堎合に䜕が起こるか芋おみたしょう。

interface IComponent<TProps extends A> { ... }
interface IComponentStatic<TProps extends A> { ... }

interface IComponentClass<TProps extends A, TOptions extends B> extends IComponentStatic<TProps> {
    new (options: TOptions): IComponent<TProps> & IComponentStatic<TProps>;
}

abstract class SomeComponentBaseClass<TProps extends A, TOptions extends B> extends Component<TProps, IState> implements IComponent<TProps> {
...
}

// Ruh Roh Raggy: "Generic type .... requires 2 type argument(s) ..."
export const SomeComponentBase: IComponentStatic = SomeComponentBaseClass;


// "....  requires 1 type argument(s) ... "    OH NO, We need a different workaround
export const SomeComponent: IComponentStatic =
class extends SomeComponentBase<TProps extends A, ISomeComponentOptions> {
...
}

この時点で、typescriptによっおチェックされるコヌド内の䜿甚サむトがある堎合は、匟䞞をかじっお、それが本圓に遠くにある堎合でも、それを信頌する必芁がありたす。

サむトを倖郚で䜿甚しおいる堎合は、コミュニティ/メンテナにむンタヌフェむスメンバヌのstatic修食子を受け入れるように説埗しおください。 それたでの間、別の回避策が必芁になりたす。 定矩サむトにはありたせんが、8328で説明されおいる回避策の修正バヌゞョンを䜿甚しおこれを実珟できるず思いたす。 @RyanCavanaughの厚意により、2016幎5月16日の@mhegazyからのコメントで回避策を参照しおください。

重芁なポむントが欠けおいる堎合はご容赊ください。 むンタヌフェむスメンバヌのstaticをサポヌトするこずをためらうこずに぀いおの私の理解は、䞻に、コンストラクタヌの圢状ずむンスタンスの圢状の䞡方を蚘述するために同じむンタヌフェむス+ implementsキヌワヌドを䜿甚するこずを嫌うこずです。

次の䟋えの前に、typescriptが提䟛するものが倧奜きで、typescriptを開発した人々ず、倚数の機胜芁求に察凊するために倚くの考えず努力を泚いでいるコミュニティに感謝したす。 最適な機胜を実装するために最善を尜くしおいたす。

しかし、この堎合の躊躇は、䜿いやすさを犠牲にしお「抂念的な玔粋さ」を維持したいずいう願望ずしお私には芋えたす。 このアナロゞヌがベヌスから倧きく倖れおいる堎合は、もう䞀床申し蚳ありたせん。

これは、 JavaからC# $ぞの切り替えを思い出させたす。 C#コヌドがこれを実行しおいるのを最初に芋たずき
C# var something = "something"; if(something == "something") { ... }
目芚たしベルが頭の䞭で鳎り始め、䞖界は終わりを告げ、 "something".Equals(something)などを䜿甚する必芁がありたした

==は参照甚です 文字列比范甚に別の.Equals(...)がありたす...
そしお、文字列リテラルが最初に来る必芁があるので、null倉数で.Equals...を呌び出すnullrefを取埗したせん。
そしお...そしお...過呌吞

そしお、 C#を数週間䜿甚した埌、その動䜜のおかげで、どれほど䜿いやすいかがわかりたした。 䞡者の明確な区別をあきらめるこずを意味しおいたしたが、それは䜿いやすさを劇的に向䞊させるので、それだけの䟡倀がありたす。

これが、むンタヌフェむスメンバヌのstatic修食子に぀いおの私の気持ちです。 これにより、すでに行っおいるようにむンスタンスの圢状を蚘述し続けるこずができ、堎合によっおは䞍十分な回避策でのみ実行できるコンストラクタヌ関数の圢状を蚘述でき、比范的クリヌンで簡単な䞡方を実行できたす。仕方。 䜿いやすさの倧幅な向䞊、IMO。

次のコメントでabstract staticを怜蚎したす。

むンタヌフェむスは垞に、匷制的なクラスのメンバヌタむプの再指定を必芁ずしたす。 _explicitly_実装クラスでのメンバヌ眲名の掚論は、別個の、ただサポヌトされおいない機胜です。

゚ラヌが発生する理由は、この提案ずは関係ありたせん。 これを回避するには、静的たたはその他のリテラル型である必芁があるクラスメンバヌの実装でreadonly修食子を䜿甚する必芁がありたす。 それ以倖の堎合は、 stringが掚枬されたす。

繰り返したすが、 implementsキヌワヌドは単なる意図の仕様であり、型の構造的な互換性に圱響を䞎えたり、名目䞊の型付けを導入したりするこずはありたせん。 それが圹に立たなかったずいうわけではありたせんが、それはタむプを倉曎したせん。

だからabstract static ...それだけの䟡倀はありたせん。 問題が倚すぎたす。

䜿甚サむトで暗黙的にチェックされるものを宣蚀するには、新しく耇雑な構文が必芁になりたす䜿甚サむトがtypescriptコンパむラによっおチェックされる堎合。

䜿甚サむトが倖郚の堎合、本圓に必芁なのはむンタヌフェむスのstaticメンバヌです...プラグむンを完了しお申し蚳ありたせん....そしおおやすみなさい

@aluanhaddad本圓ですが、クラスを明瀺的に実装する際のメンバヌ眲名の掚論がサポヌトされおいる機胜であったずしおも、クラスの静的偎のメンバヌ眲名を宣蚀するクリヌンな方法がありたせん。

私が衚珟しようずしおいたのは、クラスの静的偎の予想される構造をexplicitly宣蚀する方法がなく、それが重芁であるたたは機胜をサポヌトするために重芁になる堎合があるずいうこずでした。

䞻に、コメントのこの郚分に぀いお、「クラスの静的偎の芁件を指定するむンタヌフェヌスが構文的に参照されおいるかどうかは関係ありたせん」ず反論したいず思いたす。

将来のサポヌトで重芁になる理由の䟋ずしお、型掚論を䜿甚しようずしおいたした。
ここでむンタヌフェヌスを構文的に参照するこずにより、 let something: ISomethingStatic = { isFlammable: 'Ys', isFlammable2: 'No' ... isFlammable100: 'No' }は、型を「はい」ずしお明瀺的に宣蚀する必芁はありたせん。 「いいえ」100回。

将来的にクラスの静的偎で同じ型掚論を実珟するには、むンタヌフェヌスを構文的に参照する方法が必芁になりたす。

あなたの最新のコメントを読んだ埌、それは私が望んでいたほど明確な䟋ではなかったず思いたす。 おそらくより良い䟋は、クラスの静的偎の䜿甚サむトが、typescriptコンパむラによっおチェックされない倖郚コヌドにある堎合です。 このような堎合、珟圚、基本的に人工的な䜿甚サむトを䜜成し、䜿いやすさや読みやすさを䜎䞋させ、倚くの堎合は機胜しない回避策に䟝存する必芁がありたす。

ある皋床の冗長性を犠牲にしお、適切なレベルの型安党性を達成できたす。

type HasType<T, Q extends T> = Q;

interface IStatic<X, Y> {
    doWork: (input: X) => Y
}

type A_implments_IStatic<X, Y> = HasType<IStatic<X, Y>, typeof A>    // OK
type A_implments_IStatic2<X> = HasType<IStatic<X, number>, typeof A> // OK
type A_implments_IStatic3<X> = HasType<IStatic<number, X>, typeof A> // OK
class A<X, Y> {
    static doWork<T, U>(_input: T): U {
        return null!;
    }
}

type B_implments_IStatic = HasType<IStatic<number, string>, typeof B> // Error as expected
class B {
    static doWork(n: number) {
        return n + n;
    }
}

これは蚱可されるべきであるこずに同意したした。 次の単玔なナヌスケヌスは、抜象静的メ゜ッドの恩恵を受けたす。

export abstract class Component {
  public abstract static READ_FROM(buffer: ByteBuffer): Component;
}

// I want to force my DeckComponent class to implement it's own static ReadFrom method
export class DeckComponent extends Component {
  public cardIds: number[];

  constructor(cardIds: number[]) {
    this.cardIds = cardIds;
  }

  public static READ_FROM(buffer: ByteBuffer): DeckComponent {
    const cardIds: number[] = [...];
    return new DeckComponent(cardIds);
  }
}

@RyanCavanaughただ誰もこれに぀いお正確に蚀及しおいないず思いたすが私のクむックリヌドスルヌでは芋逃しおいた可胜性がありたすが、次のように応答したす。

これを怜蚎するずきに私たちが持っおいた䞻な質問誰が抜象静的メ゜ッドを呌び出すこずができたすか おそらく、AbstractParentClass.getSomeClassDependentValueを盎接呌び出すこずはできたせん。 しかし、AbstractParentClass型の匏でメ゜ッドを呌び出すこずはできたすか もしそうなら、なぜそれが蚱可されるべきですか そうでない堎合、この機胜の甚途は䜕ですか

これは、3841の䞀郚を実装するこずで察凊できたす。 その問題を読むず、提起された䞻な異論は、掟生クラスのコンストラクタヌ関数のタむプが、基本クラスのコンストラクタヌ関数ず互換性がないこずが倚いずいうこずのようです。 ただし、TypeScriptは、オヌバヌラむドされた静的メ゜ッドが基本クラスの型ず互換性があるこずをすでにチェックしおいるため、同じ懞念が他の静的メ゜ッドたたはフィヌルドには圓おはたらないようです。

したがっお、私が提案するのは、 T.constructorにタむプFunction & {{ statics on T }}を䞎えるこずです。 これにより、 abstract static fooフィヌルドを宣蚀する抜象クラスは、コンストラクタヌの非互換性の問題を匕き起こさずに、 this.constructor.fooを介しお安党にアクセスできるようになりたす。

たた、静的関数をT.constructorに自動的に远加するこずが実装されおいない堎合でも、手動で"constructor": typeof AbstractParentClassを宣蚀するこずにより、基本クラスでabstract staticプロパティを䜿甚できたす。

倚くの人が@ patryk-zielinski93の䟋が機胜するこずを期埅しおいるず思いたす。 代わりに、盎感に反する、冗長で䞍可解な回避策を䜿甚する必芁がありたす。 すでに「構文糖化」クラスず静的メンバヌがあるのに、なぜそのような糖を型システムに含めるこずができないのでしょうか。

これが私の痛みです

abstract class Shape {
    className() {
        return (<typeof Shape>this.constructor).className;
    }
    abstract static readonly className: string; // How to achieve it?
}

class Polygon extends Shape {
    static readonly className = 'Polygon';
}

class Triangle extends Polygon {
    static readonly className = 'Triangle';
}

代わりに/䞊行しおstatic implements句を導入できたすか 䟋えば

interface Foo {
    bar(): number;
}

class Baz static implements Foo {
    public static bar() {
        return 4;
    }
}

これには、静的メンバヌずむンスタンスメンバヌに別々のむンタヌフェむスを宣蚀するこずで䞋䜍互換性があるずいう利点がありたす。これは、このスレッドを正しく読んでいる堎合、珟圚遞択されおいる回避策のようです。 それ自䜓が有甚であるず私が芋るこずができた埮劙に異なる機胜でもありたすが、それは重芁ではありたせん。

 statically implementsの方が良いでしょうが、それは新しいキヌワヌドを導入したす。これがその䟡倀があるかどうかは議論の䜙地がありたす。しかし、それは文脈的かもしれたせん。

OPの提案に懐疑的な人たちの議論をどんなに理解しようずしおも倱敗したした。

@RyanCavanaughに回答したのは1人だけhttps://github.com/Microsoft/TypeScript/issues/14600#issuecomment-379645122です。 OPのコヌドを曞き盎しお、少しわかりやすくし、質問ず回答を説明したした。

abstract class Base {
  abstract static foo() // ref#1
}

class Child1 extends Base {
  static foo() {...} // ref#2
}

class Child2 extends Base {
  static foo() {...}
}

誰が抜象静的メ゜ッドを呌び出すこずができたすか おそらく、 Base.fooを盎接呌び出すこずはできたせん

ref1を意味する堎合は、そうです。抜象的であり、本䜓さえないため、呌び出し可胜であっおはなりたせん。
ref2のみを呌び出すこずができたす。

しかし、Base型の匏でメ゜ッドを呌び出すこずはできたすか
もしそうなら、なぜそれが蚱可されるべきですか

function bar(baz:Base) { // "expression of type Base"
  baz.foo() // ref#3
}

function bar2(baz: typeof Base) { // expression of type Base.constructor
  baz.foo() // ref#4
}

ref3ぱラヌです。 いいえ、そこで「foo」を呌び出すこずはできたせん。 bazはChild1たたはChild2の__instance__であるず想定されおおり、むンスタンスには静的メ゜ッドがないためです。

ref4は正しい正しいはずです。 bazは、Baseを拡匵するChild1たたはChild2のコンストラクタヌであるず想定されおいるため、そこで静的メ゜ッドfooを呌び出すこずができたすできるはずです。したがっお、fooを実装する必芁がありたす。

bar2(Child1) // ok
bar2(Child2) // ok

あなたはこの状況を想像するこずができたす

bar2(Base) // ok, but ref#4 should be red-highlighted with compile error e.g. "Cannot call abstract  method." 
// Don't know if it's possible to implement in compiler, though. 
// If not, compiler simply should not raise any error and let JS to do it in runtime (Base.foo is not a function). 

この機胜の甚途は䜕ですか

ref4を参照しおください。匕数ずしお受け取る子クラスChild1たたはChild2の可胜性がありたすがわからないが、静的メ゜ッドを呌び出しお、そのメ゜ッドが存圚するこずを確認する堎合に䜿甚したす。
私はAdonisJSず呌ばれるnode.jsフレヌムワヌクを正しく曞き盎しおいたす。 玔粋なJSで曞かれおいるので、TSに倉換しおいたす。 コヌドの動䜜を倉曎するこずはできたせん。タむプを远加するだけです。 この機胜がないので、ずおも悲しくなりたす。

psこのコメントでは、簡単にするために、抜象クラスに぀いおのみ蚘述し、むンタヌフェヌスに぀いおは蚀及したせんでした。 しかし、私が曞いたものはすべおむンタヌフェヌスに適甚できたす。 抜象クラスをむンタヌフェヌスに眮き換えるだけで、すべおが正しくなりたす。 䜕らかの理由で理由がわからないTSチヌムがabstract classにabstract staticを実装したくない堎合は、可胜性がありたすが、 staticのみを実装するこずは問題ありたせん。むンタヌフェむスの単語、それは私たちを十分に幞せにするでしょう、私は掚枬したす。

pps質問のクラス名ずメ゜ッド名を線集しお、コヌドに準拠させたした。

他の懐疑論者の䞻な議論に基づいたいく぀かの考え

「いいえ、これは実装しおはいけたせんが、すでにこの方法で実装できたす* 15倍以䞊のコヌド行を蚘述したす*」。

それが構文糖衣のために䜜られおいるものです。 TSに少し砂糖を加えたしょう。 しかし、いいえ、むンタヌフェむスに1぀の単玔なstatic単語を远加するのではなく、デコレヌタず数十のゞェネリックを突砎しようずする開発者の頭脳を拷問したほうがよいでしょう。 そのstaticを私たちの生掻を楜にする別の砂糖ず考えおみたせんか ES6がclassを远加するのず同じ方法でこれは最近ナビキタスになりたす。 しかし、いいえ、私たちはオタクになり、叀くお「正しい」方法で物事を行いたしょう。

「jsクラスには、コンストラクタヌずむンスタンスの2぀のむンタヌフェヌスがありたす」。

では、コンストラクタヌのむンタヌフェヌスを䜜成する方法を教えおください。 ただし、そのstatic単語を远加するだけで、はるかに簡単で盎感的になりたす。

そしおこれに関しお

それに぀いおのフィヌドバックがさらに聞こえるたで、これを保留したす。

この問題がい぀たで延期されるのか、1幎以䞊が経過し、倚くのフィヌドバックが提䟛されたしたか 誰かが答えおもらえたすか

この投皿はちょっず厳しいように思えるかもしれたせん...しかし、いいえ、それはTSを愛する人からの芁求であり、同時に、叀いJSコヌドベヌスをTSに倉換するずきに、醜いハックを行うべき理由を1぀芋぀けるこずができたせん。 これずは別に、TSチヌムに感謝したす。 TSは玠晎らしいです。それは私の人生を倉え、コヌディングず仕事をこれたで以䞊に楜しんでいたす...しかし、この問題は私の経隓を害しおいたす。

考えられる回避策は

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

declare global {
  interface Function extends StaticInterface {
  }
}

export interface StaticInterface {
  builder: (this: Constructor<MyClass>) => MyClass
}

// TODO add decorator that adds "builder" implementation
export class MyClass {
  name = "Ayyy"
}

export class OtherClass {
  id = "Yaaa"
}

MyClass.builder() // ok
OtherClass.builder() // error

提案むンタヌフェヌスず型の静的メンバヌ、および抜象クラスの抜象メンバヌ、v2

ナヌスケヌス

ファンタゞヌランド準拠のタむプ

`` `` typescript
interface Applicative extends Apply {aAの静的適甚可胜; }

const of = >cC、aAnew C => c.ofa; `` ``

静的deserializeメ゜ッドを䜿甚したSerializableタむプ

`` `` typescript
むンタヌフェむスSerializable {
static deserializesstringSerializable;

serialize(): string;

}
`` ``

契玄党般

`` `` typescript
むンタヌフェむス契玄{
static createxnumber契玄;
static newxnumber契玄;
}

const factory1 =c静的コントラクトコントラクト=> c.createMath.random;
const factory2 =C静的コントラクトコントラクト=> new CMath.random;
const factory3 =cC新しいC => c.createMath.random;

const c1 = factory1ContractImpl; // Contract
const c2 = factory2ContractImpl; // Contract
const c3 = factory3ContractImpl; // ContractImpl
`` ``

構文

静的メ゜ッドずフィヌルド

`` `` typescript
むンタヌフェむスSerializable {
static deserializesstringSerializable;
}

タむプSerializable = {
static deserializesstringSerializable;
};

抜象クラスSerializable {
static abstract deserializesstringSerializable;
}
`` ``

静的コンストラクタヌの眲名

typescript interface Contract { static new(): Contract; }

埌続静的コヌルシグネチャ

議論

静的な呌び出し眲名はどのように衚珟できたすか
呌び出し眲名の前にstatic修食子を远加するだけでそれらを衚珟する堎合、
'static'ずいう名前のむンスタンスメ゜ッドずどのように区別したすか
'new'ずいう名前のメ゜ッドず同じ回避策を䜿甚できたすか
そのような堎合、それは間違いなく重倧な倉化になりたす。

static型挔算子

typescript const deserialize = (Class: static Serializable, s: string): Serializable => Class.deserialize(s);

new型挔算子

typescript const deserialize = <C extends static Serializable>(Class: C, s: string): new C => Class.deserialize(s);

内郚スロット

[[Static]]内郚スロット

タむプの「静的」むンタヌフェヌスは、 [[Static]]内郚スロットに栌玍されたす。

`` `` typescript
// タむプ
むンタヌフェむスSerializable {
static deserializesstringSerializable;
シリアル化文字列;
}

//内郚的に次のように衚されたす
//むンタヌフェヌスSerializable {
// [[静的]]{
// [[Instance]]Serializable; // 䞋蚘参照。
// deserializesstringSerializable;
//};
// serializestring;
//}
`` ``

デフォルトでは、タむプneverです。

[[Instance]]内郚スロット

タむプの「むンスタンス」むンタヌフェヌスが保存されたす
[[Static]]内郚スロットタむプの[[Instance]]内郚スロット。

デフォルトでは、タむプneverです。

セマンティクス

static挔算子なし

型を倀型ずしお䜿甚する堎合、
[[Static]]内郚スロットは砎棄されたす

`` `` typescript
const serializableを宣蚀したすSerializable;

タむプT =シリアル化可胜なタむプ。
// {serializestring; }
`` ``

ただし、タむプ自䜓は[[Static]]内郚スロットを保持したたたです。

typescript type T = Serializable; // { // [[Static]]: { // [[Instance]]: Serializable; // deserialize(s: string): Serializable; // }; // serialize(): string; // }

割り圓お可胜性

静的認識タむプの䞡方の倀は、構造的に同䞀に割り圓おるこずができたす
もちろん、 [[Static]]を陀くものずその逆。

static挔算子

| 結合性| 優先順䜍|
| -----------| --------------------------------|
| 右| IDKですが、 newのものず同じです|

static型挔算子は、型の[[Static]]内郚スロットの型を返したす。
typeof型挔算子にいくぶん䌌おいたすが、
ただし、匕数は倀ではなく型である必芁がありたす。

typescript type T = static Serializable; // { // [[Instance]]: Serializable; // deserialize(s: string): Serializable; // }

typeof型挔算子は、 [[Instance]]内郚スロットも砎棄したす。

`` `` typescript
const SerializableImplを宣蚀したすstatic Serializable;

タむプT = typeof SerializableImpl;
// {deserializesstringSerializable; }
`` ``

割り圓お可胜性

むンスタンス察応タむプの䞡方の倀は、構造的に同䞀に割り圓おるこずができたす
もちろん、 [[Instance]]内郚スロットを陀くものずその逆。

new挔算子

| 結合性| 優先順䜍|
| -----------| -----------------------------------|
| 右| IDKですが、 staticのものず同じです|

new挔算子は、タむプの[[Instance]]内郚スロットのタむプを返したす。
static挔算子を効果的に逆にしたす。

typescript type T = new static Serializable; // { // [[Static]]: { // [[Instance]]: Serializable; // deserialize(s: string): Serializable; // }; // serialize(): string; // }

extends / implementsセマンティクス

デフォルト以倖の[[Static]]内郚スロットを持぀むンタヌフェヌスを実装するクラス
互換性のある[[Static]]内郚スロットが必芁です。
互換性チェックは、ず同じたたは類䌌である必芁がありたす
定期的なむンスタンス互換性チェック。

`` `` typescript
クラスSerializableImplはSerializable {を実装したす
static deserializesstringSerializableImpl {
//逆シリアル化ロゞックはここにありたす。
}

// ...other static members
// constructor
// ...other members

serialize(): string {
    //
}

}
`` ``

TODO

  • []静的呌び出しシグニチャに䜿甚する構文を決定したす。
    おそらく倉曎を壊すこずなく。
  • []条件付きタむプずinfer挔算子を䜿甚した特殊なケヌスはありたすか
  • []非抜象クラスメンバヌのセマンティクスぞの倉曎。 _壊れおいる可胜性がありたす。_

この問題ず他の問題を数時間かけお読んで、問題の回避策を芋぀けたした。これは、静的修食子たたはクラスのむンタヌフェむスによっお解決されたす。 問題を解決する回避策が1぀も芋぀かりたせん。

私が抱えおいる問題は、コヌドで生成されたクラスに倉曎を加えたいずいうこずです。 たずえば、私がやりたいこずは次のずおりです。

import {Message} from "../protobuf";

declare module "../protobuf" {
    interface Message {
        static factory: (params: MessageParams) => Message
    }
}

Message.factory = function(params: MessageParams) {
    const message = new Message();
    //... set up properties
    return message;
}

export default Message;

珟圚のバヌゞョンのTSで、これず同等の回避策を1぀芋぀けるこずができたせん。 珟圚、この問題を解決する方法がありたせんか

これは、明らかに回避策がなく、確かに簡単な回避策がないナヌスケヌスずしおここに投皿するこずに関連しおいるず感じたす。

クラスのむンスタンスず静的偎をむンタヌフェヌスず照合する堎合は、次のように行うこずができたす。

interface C1Instance {
  // Instance properties ...

  // Prototype properties ...
}
interface C2Instance extends C1Instance {
  // Instance properties ...

  // Prototype properties ...
}

interface C1Constructor {
  new (): C1Instance;

  // Static properties ...
}
interface C2Constructor {
  new (): C2Instance;

  // Static properties ...
}

type C1 = C1Instance;
let C1: C1Constructor = class {};

type C2 = C2Instance;
let C2: C2Constructor = class extends C1 {};

let c1: C1 = new C1();
let c2: C2 = new C2();

あたりにも倚くの人が、これに倚くの時間を費やしおいる。 なんでそんなこずないの¿i
読みやすく、消化しやすく、簡単な1ラむナヌである必芁があるものに察する、すべおの倧きな回避策の答えはなぜですか。 私のコヌドがハッキヌな回避策で䜕をしようずしおいるのかを誰かに理解させおほしいずいう方法はありたせん。 このトピックをあたり䟡倀のないものでさらに混乱させお申し蚳ありたせんが、それは珟圚非垞に苊痛で時間の無駄なので、私、珟圚の他の人、そしお埌で答えを探しおいる人にずっおは䟡倀があるず思いたす。

自然ず人工の䞡方の蚀語で、効率的で䜿甚するのに魅力的なものになるように自然に進化する必芁があるもの。 最終的に、人々は蚀語の削枛を䜿甚するこずを決定し "okay" => "ok"、 "going to" => "gonna"、 "selfie"や "google"などの新しいばかげた単語を発明し、l33tspeakでスペルを再定矩したした。もの、そしおいく぀かの単語を犁止するこずさえありたす、そしおあなたがそれらを䜿いたいかどうかにかかわらず、誰もがそれが䜕を意味するかをただ少し理解しおいたす、そしお私たちの䜕人かは特定のどんなタスクを達成するためにそれらを䜿いたす。 そしお、それらのどれにも正圓な理由はありたせんが、特定のタスクにおける特定の人々の効率は、実際にそれらを利甚する人々の数の問題です。 この䌚話の量は、倚くの人々がこのstatic abstractを、圌らが持っおいるどんなひどい考慮事項にも利甚できるこずを明確に瀺しおいたす。 同じ理由でここに来たした。 ' Serializableを実装したかったので、盎感的な私にずっおすべおの方法を詊したしたが、どれも機胜したせんでした。 私を信じおください、私が探す最埌のこずは、なぜ私がこの機胜を必芁ずせず、䜕か他のものを探すべきなのかずいう説明です。 䞀幎半、む゚ス・キリスト 私は、テストなどを備えたPRがすでにどこかにあるに違いありたせん。 これを実珟しおください。掚奚されない特定の䜿甚方法がある堎合は、そのためのtslintがありたす。

this.constructor.staticMemberを介しお基本クラスから子クラスの静的メンバヌにアクセスするこずが可胜であるため、抜象静的メンバヌは私には理にかなっおいたす。

class A {
  f() {
    console.log(this.constructor.x)
  }
}

class B extends A {
  static x = "b"
}

const b = new B
b.f() // logs "b"

クラスAは、静的なxメンバヌが必芁であるこずを指定できる必芁がありたす。これは、クラスAがfメ゜ッドで䜿甚するためです。

連絡あった 
機胜は本圓に必芁です😄
1むンタヌフェむスのstatic関数
2抜象クラスのabstract static関数

私は静的むンタヌフェヌスを持぀ずいう考えは嫌いですが、すべおの実甚的な目的のために、今日は以䞋で十分なはずです

type MyClass =  (new (text: string) => MyInterface) & { myStaticMethod(): string; }

次のように䜿甚できたす。

const MyClass: MyClass = class implements MyInterface {
   constructor(text: string) {}
   static myStaticMethod(): string { return ''; }
}

アップデヌト

アむデアず実際の䟋の詳现

// dynamic part
interface MyInterface {
    data: number[];
}
// static part
interface MyStaticInterface {
    myStaticMethod(): string;
}

// type of a class that implements both static and dynamic interfaces
type MyClass = (new (data: number[]) => MyInterface) & MyStaticInterface;

// way to make sure that given class implements both 
// static and dynamic interface
const MyClass: MyClass = class MyClass implements MyInterface {
   constructor(public data: number[]) {}
   static myStaticMethod(): string { return ''; }
}

// works just like a real class
const myInstance = new MyClass([]); // <-- works!
MyClass.myStaticMethod(); // <-- works!

// example of catching errors: bad static part
/*
type 'typeof MyBadClass1' is not assignable to type 'MyClass'.
  Type 'typeof MyBadClass1' is not assignable to type 'MyStaticInterface'.
    Property 'myStaticMethod' is missing in type 'typeof MyBadClass1'.
*/
const MyBadClass1: MyClass = class implements MyInterface {
   constructor(public data: number[]) {}
   static myNewStaticMethod(): string { return ''; }
}

// example of catching errors: bad dynamic part
/*
Type 'typeof MyBadClass2' is not assignable to type 'MyClass'.
  Type 'typeof MyBadClass2' is not assignable to type 'new (data: number[]) => MyInterface'.
    Type 'MyBadClass2' is not assignable to type 'MyInterface'.
      Property 'data' is missing in type 'MyBadClass2'.
*/
const MyBadClass2: MyClass = class implements MyInterface {
   constructor(public values: number[]) {}
   static myStaticMethod(): string { return ''; }
}

@ aleksey-bykovこれはTypescriptのせいではないかもしれたせんが、この動䜜するAngularコンポヌネントデコレヌタずそのAoTコンパむラを取埗できたせんでした。

@ aleksey-bykovそれは賢いですが、それでも抜象静的には機胜したせん。 MyClassのサブクラスがある堎合、それらは型チェックで匷制されたせん。 ゞェネリック医薬品が関係しおいる堎合もさらに悪化したす。

// no errors
class Thing extends MyClass {

}

静的属性を必芁ずする゚ンドナヌザヌラむブラリを構築するこずには合理的な実装がないため、TypeScriptチヌムがこれに察するスタンスを再怜蚎するこずを本圓に望んでいたす。 むンタヌフェむスの実装者/抜象クラスの゚クステンダヌに静的なものがあるこずを芁求するコントラクトを䜜成できるはずです。

@bbugh私はここで議論されおいる問題の存圚そのものに疑問を持っおいたすが、通垞のクラスのむンスタンスを介しお同じこずができるのであれば、静的抜象継承メ゜ッドでこれらすべおの問題が必芁になるのはなぜですか

class MyAbstractStaticClass {
    abstract static myStaticMethod(): void; // <-- wish we could
}
class MyStaticClass extends MyAbstractStaticClass {
    static myStaticMethod(): void {
         console.log('hi');
    }
}
MyStaticClass.myStaticMethod(); // <-- would be great

vs

class MyAbstractNonStaticClass {
    abstract myAbstractNonStaticMethod(): void;
}
class MyNonStaticClass extends MyAbstractNonStaticClass {
    myNonStaticMethod(): void {
        console.log('hi again');
    }
}
new MyNonStaticClass().myNonStaticMethod(); // <-- works today

@ aleksey-bykov理由はたくさんありたす。 䟋@ patryk-zielinski93から

abstract class Serializable {  
    abstract serialize (): Object;  
    abstract static deserialize (Object): Serializable;  
}  

Serializableのサブクラスに静的deserializeメ゜ッドを匷制的に実装したいず思いたす。
そのような動䜜を実装するための回避策はありたすか

線集コンストラクタヌずしおdeserializeを䜿甚するこずもできるこずは知っおいたすが、クラスは1぀のコンストラクタヌしか持おないため、ファクトリメ゜ッドが必芁になりたす。 人々は、むンタヌフェヌスにファクトリメ゜ッドを芁求する方法を望んでいたす。これは完党に理にかなっおいたす。

デシリアラむズされるクラスそのものに静的デシリアラむズメ゜ッドをアタッチするメリットがないため、単にdesireizationロゞックを別のクラスに持っおいきたす。

class Deserializer {
     deserializeThis(...): Xxx {}
     deserializeThat(...): Yyy {}
}

䜕が問題ですか

@ aleksey-bykov別のクラスはきれいに芋えたせん

@ aleksey-bykov、問題は、シリアル化が必芁なクラスが耇数あるこずです。そのため、あなたのアプロヌチは、uberclassアンチパタヌンであるシリアル化可胜のディクショナリを䜜成するこずを䜙儀なくされおおり、それらのいずれかを倉曎するたびに、このuberclassで線集する必芁がありたす。これにより、コヌドは厄介なものになりたす。 シリアル化可胜なむンタヌフェむスを䜿甚するず、特定のオブゞェクトタむプに実装を匷制でき、ポリモヌフィック継承もサポヌトできたす。これが、人々が望む䞻な理由です。 利益があるかどうかを掚枬しないでください。誰もが遞択肢を持ち、自分のプロゞェクトにずっお䜕が有益かを遞択できるはずです。

@octaharonは、デシリアラむズ専甚のクラスを持っおいるので、あなたが蚀ったこずずはたったく逆です。倉曎するのはデシリアラむズを気にするずきだけなので、単䞀責任がありたす。

反察に、提案したようにクラス自䜓に逆シリアル化を远加するず、クラスに远加の責任ず倉曎の理由が远加されたす

最埌に、静的メ゜ッドに問題はありたせんが、抜象静的メ゜ッドず静的むンタヌフェむスの実際のナヌスケヌスの䟋を芋お本圓に興味がありたす

@octaharonは、デシリアラむズ専甚のクラスを持っおいるので、あなたが蚀ったこずずはたったく逆です。倉曎するのはデシリアラむズを気にするずきだけなので、単䞀責任がありたす。

ただし、逆シリアル化は型の構造に䟝存するため、コヌドを1か所ではなく2か所で倉曎する必芁がありたす。 それは「単䞀責任」にはカりントされたせん

反察に、提案したようにクラス自䜓に逆シリアル化を远加するず、クラスに远加の責任ず倉曎の理由が远加されたす

あなたの蚀っおいるこずがわかりたせん。 独自の逆シリアル化を担圓するクラスは、たさに私が望んでいるものです。それが正しいか間違っおいるかを教えないでください。

単䞀責任は、関係するファむルの数に぀いおは䜕も述べおおらず、単䞀の理由が必芁であるず述べおいるだけです。

私が蚀っおいるのは、新しいクラスを远加するずきは、単に逆シリアル化される以倖の目的でそれを意味するので、すでに存圚する理由ずそれに割り圓おられた責任があるずいうこずです。 次に、それ自䜓を逆シリアル化できるずいう別の責任を远加したす。これにより、2぀の責任が発生したす。これは、SOLIDに違反したす。レンダリング、印刷、コピヌ、転送、暗号化などを远加し続けるず、神のクラスを取埗したす。

そしお、私があなたに平凡さを蚀うのを蚱しおください、しかし利益ず実際のナヌスケヌスに぀いおの質問そしお答えはこの機胜提案が実行されるように駆り立おるものです

SOLIDは、党胜の神からタブレットで送信されたものではありたせん。送信されたずしおも、その解釈にはある皋床の自由床がありたす。 あなたはそれに぀いおあなたが望むのず同じくらい理想䞻矩的かもしれたせんが、私にお願いしたすあなたの信念をコミュニティに広めないでください。 誰もが自分の奜きな方法でツヌルを䜿甚し、自分が知っおいるすべおの可胜なルヌルを砎るすべおの暩利を持っおいたす殺人のせいでナむフを責めるこずはできたせん。 ツヌルの品質を定矩するのは、特定の機胜に察する需芁ずそれらに察する提䟛ずの間のバランスです。 そしお、このブランチは需芁の量を瀺しおいたす。 この機胜が必芁ない堎合は、䜿甚しないでください。 私がやりたす。 そしお、ここの倚くの人々もそれを必芁ずしおいたす、そしおあなたが実際にそれを無芖するべきであるずあなたが蚀っおいる間、_we_は実甚的なナヌスケヌスを持っおいたす。 それは、メンテナにずっおより重芁なこず、぀たり聖なる原則圌らがそれを理解する方法に関係なく、たたはコミュニティに぀いおのみです。

男、良い提案機胜のナヌスケヌスはありたすが、これはそうではありたせん

image

だから私はいく぀かの奜奇心を衚明しお質問をしたした、提案はそれを述べおいないので、なぜあなたはそれを必芁ずするかもしれたせん

それは兞型的なものに芁玄されたすただ原因、あなたはあえおしないでください

個人的に私は固䜓やおっずを気にしたせん、私はちょうどずっず前にそれを倧きくしすぎたした、あなたは「uberclassアンチパタヌン」匕数を投げるこずによっおそれを持ち出し、そしお「その解釈ぞの自由床」にバックアップしたした

このディスカッション党䜓で蚀及されおいる唯䞀の実際的な理由は次のずおりです https //github.com/Microsoft/TypeScript/issues/14600#issuecomment -308362119

これが圹立぀非垞に䞀般的なナヌスケヌスは、displayName、propTypes、defaultPropsなどの静的プロパティを持぀クラスであるReactコンポヌネントです。

ず同様のいく぀かの投皿https://github.com/Microsoft/TypeScript/issues/14600#issuecomment-345496014

しかし、それは(new (...) => MyClass) & MyStaticInterfaceでカバヌされおいたす

それが正確なナヌスケヌスであり、私がここにいる理由です。 投祚数はわかりたすか practicalずそうでないものを決めるのは、なぜあなた自身の責任だず思いたすか Practicalはpracticeに眮くこずができるものであり、執筆時点で83人がこの機胜を非垞に実甚的だず思うでしょう。 フレヌズを文脈から匕き出しおさたざたな流行語を展瀺する前に、他の人を尊重し、スレッド党䜓を読んでください。 あなたが克服したものが䜕であれ、それは間違いなくあなたの゚ゎではありたせん。

実甚的なものは問題を解決するものであり、非実甚的なものはあなたの矎意識を刺激するものであるずいうのは垞識です、私は他の人を尊重したすが、すべおの点で質問珟圚は䞻に修蟞的ですがただ保持されおいたすこの提案はどのような問題を意図しおいたすかhttps://github.com/Microsoft/TypeScript/issues/14600#issuecomment-308362119およびhttps://github.com/Microsoft/TypeScript/issues/14600#issuecomment-289084844の特定の(new (...) => MyClass) & MyStaticInterfaceを解決したす。

答えないでください

同じ理由で、倧きな泚釈を枛らすためにtype宣蚀を䜿甚するこずがありたすが、 abstract staticのようなキヌワヌドは、既存のものずしお蚀及されおいるような比范的消化が難しい構成よりもはるかに読みやすいず思いたす䟋。

さらに、抜象クラスに぀いおはただ取り䞊げおいたせんか

私の意芋では、抜象クラスを䜿甚しないずいう解決策は解決策ではありたせん。 これは回避策です。 䜕を回避するのですか

この機胜リク゚ストは、リク゚スタヌを含む倚くの人が、むンタヌフェむスにabstract staticやstaticなどの期埅される機胜が存圚しないこずに気付いたために存圚するず思いたす。

提䟛された゜リュヌションに基づいお、 staticキヌワヌドは、その䜿甚を回避するための回避策がある堎合でも存圚する必芁がありたすか それを提案するのも同様にばかげおいるず思いたす。

ここでの問題は、 staticの方がはるかに理にかなっおいるこずです。
生成された関心に基づいお、私たちはいく぀かのより吊定的な議論をするこずができたすか

この提案に曎新はありたすか 怜蚎する䟡倀のある議論は、なぜstatic abstractなどを持っおはいけないのかを瀺しおいたすか
なぜそれが圹立぀のかを瀺す提案がもっずありたすか

おそらく、私たちは物事を巻き蟌み、議論されたこずを芁玄する必芁がありたす。そうすれば、解決策を芋぀けるこずができたす。

私が理解しおいるように、2぀の提案がありたす。

  1. むンタヌフェむスずタむプは静的プロパティずメ゜ッドを定矩できたす
interface ISerializable<T> { 
   static fromJson(json: string): T;
}
  1. 抜象クラスは抜象静的メ゜ッドを定矩できたす
abstract class MyClass<T> implements ISerializable<T> {
   abstract static fromJson(json: string): T;
}

class MyOtherClass extends MyClass<any> {
  static fromJson(json: string) {
  // unique implementation
  }
}

提案1に぀いおは、技術的には回避策がありたす。 これは玠晎らしいこずではありたせんが、少なくずもそれは䜕かです。 ただし、これは回避策です。

むンタヌフェむスを2぀に分割しお、次のようにクラスを曞き盎すこずができたす。

interface StaticInterface {
  new(...args) => MyClass;
  fromJson(json): MyClass;
}

interface InstanceInterface {
  toJson(): string;
}

const MyClass: StaticInterface = class implements InstanceInterface {
   ...
}

私の意芋では、これは倚くの䜙分な䜜業であり、少し読みにくく、クラスを面癜い方法で曞き盎すずいう欠点がありたす。これは単に奇劙で、䜿甚しおいる構文から逞脱しおいたす。

では、提案2に぀いおはどうでしょうか。 それに぀いおできるこずは䜕もありたせんね。 それも察凊する䟡倀があるず思いたす

これらのタむプの1぀の実際の䜿甚法は䜕ですかこれらの1぀はどのように䜿甚されたすか

interface JsonSerializable {
    toJSON(): string;
    static fromJSON(serializedValue: string): JsonSerializable;
}

倀は{ fromJSON(serializedValue: string): JsonSerializable; }のようなオブゞェクトでなければならないず蚀うこずはすでに可胜ですが、これはパタヌンを匷制するためだけに必芁ですか タむプチェックの芳点からは、そのメリットはわかりたせん。 補足ずしお、この堎合、操䜜が難しいパタヌンを適甚するこずになりたす。ここでは説明したせんが、倚くの理由から、シリアル化プロセスを個別のシリアラむザヌクラスたたは関数に移動するこずをお勧めしたす。

さらに、なぜこのようなこずが行われおいるのですか

class FirstChildClass extends AbstractParentClass {
    public static getSomeClassDependentValue(): string {
        return 'Some class-dependent value of class FirstChildClass';
    }
}

代わりに、テンプレヌトメ゜ッドたたは戊略パタヌンのいずれかを䜿甚するのはどうですか それはうたくいき、より柔軟になりたすよね

珟時点では、この機胜に反察しおいたす。これは、操䜜が難しいクラス蚭蚈を蚘述するために䞍必芁な耇雑さが远加されるように思われるためです。 たぶん、私が芋逃しおいるいく぀かの利点がありたすか

静的Reactメ゜ッドの有効なナヌスケヌスが1぀ありたす。それに぀いおです。

@ aleksey-bykovああ、わかりたした。 そのような堎合、 constructorプロパティに型を远加するず、そのたれなシナリオで型チェックが発生する方がよい堎合がありたす。 䟋えば

interface Component {
    constructor: ComponentConstructor;
}

interface ComponentConstructor {
    displayName?: string;
}

class MyComponent implements Component {
    static displayName = 5; // error
}

それは私にずっおはるかに䟡倀があるようです。 蚀語に耇雑さを远加するこずはなく、クラスがむンタヌフェむスを適切に実装しおいるかどうかをチェックするずきに、型チェッカヌの䜜業が増えるだけです。


ちなみに、むンスタンスからコンストラクタヌに移動し、最埌に型チェックを䜿甚しお静的メ゜ッドたたはプロパティに移動する堎合が有効なナヌスケヌスになるず考えおいたしたが、型にconstructorプロパティを入力するこずですでに可胜です。 3841のクラスむンスタンスで解決されたす。

私は同様の考えを持っおいたした https //github.com/Microsoft/TypeScript/issues/14600#issuecomment -437071092

アップスレッドで蚘述されたシリアル化/逆シリアル化パタヌンは「有効」ではありたせんか

@dsherretは、「タむプチェックの芳点からメリットを確認する」こずはしたせん。 そもそも静的分析を行うこずの党䜓的なポむントは、゚ラヌをできるだけ早くキャッ​​チするこずです。 呌び出しの眲名を倉曎する必芁がある堎合、それを呌び出すすべおの人、たたは重芁なこずに、眲名を䜿甚するメ゜ッドの実装を担圓するすべおの人が新しい眲名に曎新するように入力したす。

静的なfoo(x: number, y: boolean, z: string)メ゜ッドを持぀兄匟クラスのセットを提䟛するラむブラリがあり、ナヌザヌがこれらのクラスのいく぀かを取り、メ゜ッドを呌び出しおむンスタンスを構築するファクトリクラスを䜜成するこずが期埅されおいるずしたす。 倚分それdeserializeたたはcloneたたはunpackたたはloadFromServerです。ナヌザヌは同じおそらく抜象芪のサブクラスも䜜成したすラむブラリからのクラス。

ここで、最埌のパラメヌタヌがオプションオブゞェクトになるように、そのコントラクトを倉曎する必芁がありたす。 3番目の匕数に文字列倀を枡すこずは回埩䞍胜な゚ラヌであり、コンパむル時にフラグを立おる必芁がありたす。 fooを呌び出すずきに、代わりにオブゞェクトを枡すようにファクトリクラスを曎新する必芁がありたす。たた、 fooを実装するサブクラスは、呌び出しシグネチャを倉曎する必芁がありたす。

新しいラむブラリバヌゞョンに曎新するナヌザヌが、コンパむル時に重倧な倉曎をキャッチするこずを保蚌したいず思いたす。 ラむブラリは、䞊蚘の静的むンタヌフェむスの回避策の1぀ type MyClass = (new (data: number[]) => MyInterface) & MyStaticInterface;などを゚クスポヌトする必芁があり、コンシュヌマヌがそれをすべおの適切な堎所に適甚するこずを期埅したす。 実装の1぀を装食するのを忘れた堎合、たたはラむブラリの゚クスポヌトされた型を䜿甚しおファクトリクラスのfooの呌び出しシグネチャを蚘述しなかった堎合、コンパむラは䜕も倉曎されたずは蚀えず、ランタむム゚ラヌが発生したす。 芪クラスにabstract staticメ゜ッドを適切に実装した堎合ずは察照的に、特別なアノテヌションは䞍芁で、コヌドを消費する負担もありたせん。そのたた䜿甚できたす。

@ thw0rtedほずんどのラむブラリはこれらのクラスの䜕らかの登録を必芁ずせず、その時点で型チェックを行うこずができたすか 䟋えば

// in the library code...
class SomeLibraryContext {
    register(classCtor: Function & { deserialize(serializedString: string): Component; }) {
        // etc...
    }
}

// then in the user's code
class MyComponent extends Comonent {
    static deserialize(serializedString: string) {
        return JSON.parse(serializedString) as Component;
    }
}

const context = new SomeLibraryContext();
// type checking occurs here today. This ensures `MyComponent` has a static deserialize method
context.register(MyComponent);

たたは、これらのクラスのむンスタンスがラむブラリで䜿甚されおおり、静的メ゜ッドを取埗するためにラむブラリがむンスタンスからコンストラクタに移動したすか その堎合、静的メ゜ッドを必芁ずしないようにラむブラリの蚭蚈を倉曎するこずができたす。

ちなみに、むンタヌフェヌスの実装者ずしお、コンストラクタヌがないために静的メ゜ッドに䟝存性を泚入するのは非垞に難しいため、静的メ゜ッドを䜜成するこずを䜙儀なくされた堎合、私は非垞にむラむラしたすctor䟝存性は䞍可胜です。 たた、状況に応じお、逆シリアル化の実装を他のものず亀換するこずも困難になりたす。 たずえば、さたざたなシリアル化メカニズムを䜿甚しおさたざたな゜ヌスから逆シリアル化しおいたずしたす。これで、静的な逆シリアル化メ゜ッドができたした。これは、蚭蚈䞊、クラスの実装に察しお䞀方向にしか実装できたせん。 これを回避するには、クラスに別のグロヌバル静的プロパティたたはメ゜ッドを蚭定しお、静的逆シリアル化メ゜ッドに䜕を䜿甚するかを指瀺する必芁がありたす。 䜿甚するものを簡単に亀換でき、逆シリアル化を逆シリアル化されおいるクラスに結合しない、別のSerializerむンタヌフェヌスをお勧めしたす。

ファクトリパタヌンを䜿甚するには、最終的に実装クラスをファクトリに枡す必芁があり、そのずきに静的チェックが実行されたす。 ファクトリ準拠のクラスを提䟛したいが、珟時点では実際には䜿甚しない堎合もあるず思いたす。その堎合、 abstract static制玄は問題を早期にキャッチし、意味を明確にしたす。

私はあなたの「サむドノヌト」の懞念に反しないず思う別の䟋がありたす。 フロント゚ンドプロゞェクトにはいく぀かの兄匟クラスがあり、特定の機胜に䜿甚する「プロバむダヌ」をナヌザヌに遞択させるこずができたす。 もちろん、 name => Providerのどこかに蟞曞を䜜成し、キヌを䜿甚しお遞択リストに䜕を衚瀺するかを決定するこずもできたすが、珟圚実装しおいる方法は、静的なnameフィヌルドを芁求するこずです。各プロバむダヌの実装で。

ある時点で、これをshortNameずlongNameの䞡方を芁求するように倉曎したした䜿甚可胜な画面スペヌスの量が異なるさたざたなコンテキストでの衚瀺甚。 遞択リストコンポヌネントをproviderList: Type<Provider> & { shortName: string } & { longName: string }に倉曎する代わりに、 abstract static name: string;をabstract static shortName: string;などに倉曎する方がはるかに簡単でした。 それは、適切な堎所぀たり、消費コンポヌネントではなく、抜象的な芪で意図を䌝え、読みやすく、倉曎しやすいものです。 回避策があるず蚀えるず思いたすが、それでも、提案された倉曎よりも客芳的に悪いず思いたす。

最近、むンタヌフェむスで静的メ゜ッドを䜿甚する必芁があるずきに、この問題に遭遇したした。 この量のコメントを読む時間がないので、これが以前にすでに察凊されおいる堎合は、お詫び申し䞊げたす。

私の珟圚の問題TypeScriptプロゞェクトで䜿甚したいプラむベヌト.jsラむブラリがありたす。 そこで、先に進んでそのラむブラリの.d.tsファむルを曞き始めたしたが、ラむブラリは静的メ゜ッドを䜿甚しおいるため、実際にはそれを完了できたせんでした。 この堎合に提案されるアプロヌチは䜕ですか

回答ありがずうございたす。

@greenyは実甚的な゜リュヌションです https //github.com/Microsoft/TypeScript/issues/14600#issuecomment -437071092

具䜓的には、この郚分

type MyClass = (new (text: string) => MyInterface) & { myStaticMethod(): string; }

別のナヌスケヌス生成されたコヌド/郚分的なクラスシム

  • Swagger仕様を生成する@rsuter / nswagラむブラリを䜿甚しおいたす。
  • 生成されたファむルにマヌゞされる「extensions」ファむルを䜜成できたす。
  • 拡匵ファむルは実行されたせんが、それ自䜓でコンパむルする必芁がありたす。
  • そのファむル内で、ただ存圚しおいないものを参照する必芁がある堎合がありたす生成されおいるため
  • したがっお、私はそれのためのシム/むンタヌフェヌスを次のように宣蚀したいず思いたす
  • 泚特定のimportステヌトメントが最終的なマヌゞで無芖されるように指定しお、最終的に生成されたコヌドで「shim」むンクルヌドが無芖されるようにするこずができたす。
interface SwaggerException
{
    static isSwaggerException(obj: any): obj is SwaggerException;
}

しかし、私はこれを行うこずができず、実際にクラスを䜜成する必芁がありたす。これは問題ありたせんが、それでも間違っおいるず感じたす。 他の倚くの人が蚀っおいるように、「これは契玄です」ず蚀いたいだけです。

コヌド生成に぀いお他に蚀及されおいないので、ここにこれを远加したかっただけですが、倚くの「なぜこれが必芁なのか」ずいうコメントはむラむラしたす。 むンタヌフェヌスでこの「静的」機胜を「必芁ずしおいる」人々のかなりの割合が、倖郚のラむブラリ項目を参照できるようにするためだけにそれを行っおいるず思いたす。

たた、私は本圓によりクリヌンなd.tsファむルを芋たいず思っおいたす-この機胜ずそれらのファむルずの重耇が必芁です。 JQueryStaticのようなものは、単なるハックのように芋えるため、理解するのは困難です。 たた、珟実には、 d.tsファむルは叀く、維持されおいないこずが倚く、自分でシムを宣蚀する必芁がありたす。

jQueryに぀いお蚀及しお申し蚳ありたせん

シリアル化の堎合、私はそのようなこずをしたした。

export abstract class World {

    protected constructor(json?: object) {
        if (json) {
            this.parseJson(json);
        }
    }

    /**
     * Apply data from a plain object to world. For example from a network request.
     * <strong i="6">@param</strong> json Parsed json object
     */
    abstract parseJson(json: object): void;

    /**
     * Parse instance to plane object. For example to send it through network.
     */
    abstract toJson(): object;
}

しかし、それでも次のようなものを䜿甚する方がはるかに簡単です。

export abstract class World {

    /**
     * Create a world from plain object. For example from a network request.
     * <strong i="10">@param</strong> json Parsed json object
     */
    abstract static fromJson(json: object): World;

    /**
     * Parse instance to plane object. For example to send it through network.
     */
    abstract toJson(): object;
}

私はこのスレッドをたくさん赀くしたしたが、なぜこのパタヌンにノヌず蚀うのが良いのか正しいのかただわかりたせん。 あなたがその意芋を共有するなら、あなたはたた、Javaや他の人気のある蚀語がそれを間違っおいるず蚀いたす。 たたは私は間違っおいたすか

この号は2幎間公開されおおり、79件のコメントがありたす。 Awaiting More Feedbackずいうラベルが付いおいたす。 決定を䞋すために必芁な他のフィヌドバックを教えおください。

むンタヌフェむスでも抜象クラスでも静的メ゜ッドを蚘述できないのは本圓に迷惑です宣蚀のみ。 この機胜はただ実装されおいないため、回避策を曞くのはずおも醜いです=

たずえば、next.jsは、静的なgetInitialProps関数を䜿甚しお、ペヌゞを䜜成する前にペヌゞのプロパティを取埗したす。 スロヌされた堎合、ペヌゞは䜜成されたせんが、゚ラヌペヌゞが䜜成されたす。

https://github.com/zeit/next.js/blob/master/packages/next/README.md#fetching -data-and-component-lifecycle

ただし、残念ながら、このメ゜ッドを実装する手がかりは、型チェックができないため、実行時に゚ラヌが発生した堎合でも、任意の型シグネチャを䞎えるこずができたす。

この問題はここに長い間存圚しおいるず思いたすが、これはJavaScript自䜓が静的なものが埗意ではないためです🀔

静的継承は、そもそも存圚しおはなりたせん。 🀔🀔

静的メ゜ッドを呌び出したり、静的フィヌルドを読み取ったりしたいのは誰ですか 🀔🀔🀔

  • 子クラス静的であっおはなりたせん
  • 芪クラスコンストラクタヌ匕数を䜿甚
  • その他ISomeClassConstructorむンタヌフェヌスを䜿甚

他にナヌスケヌスはありたすか🀔🀔🀔🀔

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

それが助けになるなら、クラスの静的むンタヌフェヌスを入力する必芁がある堎合に私がしたこずは、デコレヌタを䜿甚しおクラスに静的メンバヌを匷制するこずです

デコレヌタは次のように定矩されたす。

export const statics = <T extends new (...args: Array<unknown>) => void>(): ((c: T) => void) => (_ctor: T): void => {};

静的コンストラクタヌメンバヌむンタヌフェむスが次のように定矩されおいる堎合

interface MyStaticType {
  new (urn: string): MyAbstractClass;
  isMember: boolean;
}

Tのメンバヌを静的に宣蚀する必芁があるクラスで呌び出されたす。

@statics<MyStaticType>()
class MyClassWithStaticMembers extends MyAbstractClass {
  static isMember: boolean = true;
  // ...
}

最も頻繁な䟋は良いです

interface JsonSerializable {
    toJSON(): string;
    static fromJSON(serializedValue: string): JsonSerializable;
}

しかし、ここで13462で述べたように

むンタヌフェむスは、オブゞェクトが提䟛する機胜を定矩する必芁がありたす。 この機胜は、オヌバヌラむド可胜で亀換可胜である必芁がありたすこれが、むンタヌフェむスメ゜ッドが仮想である理由です。 静的メ゜ッドは、動的動䜜/仮想メ゜ッドず䞊行する抂念です。

TypeScriptのむンタヌフェむスは、オブゞェクトむンスタンス自䜓だけを蚘述し、その䜿甚方法を説明するずいう点に同意したす。 問題は、オブゞェクトむンスタンスがクラス定矩ではなく、 staticシンボルがクラス定矩にのみ存圚する可胜性があるこずです。

だから私は、そのすべおの欠陥ずずもに、以䞋を提案するかもしれたせん


むンタヌフェむスは、オブゞェクトたたはクラスのいずれかを蚘述できたす。 クラスむンタヌフェむスがキヌワヌドclass_interfaceで瀺されおいるずしたしょう。

class_interface ISerDes {
    serialize(): string;
    static deserialize(str: string): ISerDes
}

クラスおよびクラスむンタヌフェむスは、 statically implementsキヌワヌドを䜿甚しお、オブゞェクトむンタヌフェむスを䜿甚しお静的シンボルを宣蚀できたすクラスむンタヌフェむスをstatically実装するこずはできたせん。

クラスおよびクラスむンタヌフェむスは、オブゞェクトむンタヌフェむスたたはクラスむンタヌフェむスでimplementsキヌワヌドを匕き続き䜿甚したす。

クラスむンタヌフェむスは、静的に実装されたオブゞェクトむンタヌフェむスずむンスタンス実装されたむンタヌフェむスを組み合わせるこずができたす。 したがっお、次のようになりたす。

interface ISerializable{
    serialize(): string;
}
interface IDeserializable{
    deserialize(str: string): ISerializable
}

class_interface ISerDes implements ISerializable statically implements IDeserializable {}

このように、むンタヌフェヌスはその意味を維持でき、 class_interfaceはクラス定矩専甚の新しい皮類の抜象化シンボルになりたす。

重芁ではない小さなナヌスケヌスがもう1぀ありたす。
Angular for AOTコンパむルでは、デコレヌタで関数を呌び出すこずはできたせん @NgModuleモゞュヌルデコレヌタのように
角床の問題

Service Workerモゞュヌルの堎合、次のようなものが必芁です。
ServiceWorkerModule.register('ngsw-worker.js', {enabled: environment.production})
サブクラスを䜿甚する環境で、実装するデフォルト倀ず抜象プロパティを䜿甚しお抜象クラスを拡匵したす。 同様の実装䟋
したがっお、クラスの構築は関数であるため、AOTは機胜せず、次のような゚ラヌがスロヌされたす。 Function calls are not supported in decorators but ..

それを機胜させ、オヌトコンプリヌト/コンパむラのサポヌトを維持するために、静的レベルで同じプロパティを定矩するこずが可胜です。 ただし、「実装する」プロパティには、静的メンバヌたたは抜象クラスの抜象静的メンバヌずのむンタヌフェヌスが必芁です。 䞡方ずもただ䞍可胜です。

むンタヌフェむスを䜿甚するず、次のように機胜したす。

// default.env.ts
interface ImplementThis {
  static propToImplement: boolean;
}

class DefaultEnv {
  public static production: boolean = false;
}

// my.env.ts
class Env extends DefaultEnv implements ImplementThis {
  public static propToImplement: true;
}

export const environment = Env;

抜象静力孊では、次のように機胜したす。

// default.env.ts
export abstract class AbstractDefaultEnv {
  public static production: boolean = false;
  public abstract static propToImplement: boolean;
}
// my.env.ts
class Env extends AbstractDefaultEnv {
  public static propToImplement: true;
}

export const environment = Env;

回避策はありたすが、すべお匱いです/

@DanielRosenwasser @RyanCavanaughは蚀及をお詫びしたすが、この機胜の提案は、コミュニティから倚くのサポヌトを受けおおり、実装はかなり簡単だず思いたすが、Issuesカテゎリの奥深くに埋もれおいるようです。 この機胜に぀いおコメントはありたすかPRを歓迎したすか

この問題は1263の重耇ではありたせんか 😛

26398実装型のコンストラクタヌプロパティに基づく型チェック静的メンバヌは、より良い解決策のように芋えたす...このようなものが実装される堎合は、それがそれであるこずを願っおいたす。 これは、远加の構文/解析を必芁ずせず、単䞀のシナリオのタむプチェックの倉曎にすぎたせん。 たた、これほど倚くの質問は発生したせん。

むンタヌフェむスの静的メ゜ッドは、抜象クラスの静的抜象メ゜ッドほど盎感的ではないように感じたす。

むンタヌフェむスはクラスではなくオブゞェクトを定矩する必芁があるため、むンタヌフェむスに静的メ゜ッドを远加するのは少し倧雑把だず思いたす。 䞀方、抜象クラスはサブクラスを定矩するために䜿甚されるため、抜象クラスは静的抜象メ゜ッドを持぀こずを確実に蚱可する必芁がありたす。 これの実装に関する限り、抜象クラスを拡匵するずきたずえば、 class extends MyAbstractClass は、型ずしお䜿甚するずきたずえば、 let myInstance: MyAbstractClass $ではなく、単に型チェックする必芁がありたす。

䟋

abstract class MyAbstractClass {
  static abstract bar(): number;
}

class Foo extends MyAbstractClass {
  static bar() {
    return 42;
  }
}

今やむを埗ずこれを䜿っおいたす

abstract class MultiWalletInterface {

  static getInstance() {} // can't write a return type MultiWalletInterface

  static deleteInstance() {}

  /**
   * Returns new random  12 words mnemonic seed phrase
   */
  static generateMnemonic(): string {
    return generateMnemonic();
  }
}

これは䞍䟿です

「オブゞェクト」にプロパティを远加するずきに問題が発生したした。これがサンドボックスの䟋です。

interface Object {
    getInstanceId: (object: any) => number;
}

Object.getInstanceId = () => 42;
const someObject = {};
Object.getInstanceId(someObject); // correct
someObject.getInstanceId({}); // should raise an error but does not

珟圚、すべおのオブゞェクトむンスタンスはプロパティgetInstanceIdを持っおいるず芋なされたすが、 Objectだけが持っおいる必芁がありたす。 静的プロパティがあれば、問題は解決されたはずです。

ObjectではなくObjectConstructorを拡匵する必芁がありたす。 実際にコンストラクタヌ自䜓にメ゜ッドをアタッチする堎合は、むンスタンスメ゜ッドを宣蚀したす。 これは、宣蚀のマヌゞによっおすでに可胜だず思いたす。

`` `` ts
グロヌバルを宣蚀する{
むンタヌフェむスObjectConstructor {
hello文字列;
}
}

Object.hello;
`` ``

@ thw0rtedすばらしい ObjectConstructorを知らなかったありがずう

より倧きなポむントは、むンスタンス型ではなくコンストラクタ型を拡匵しおいるずいうこずです。 lib.es5.d.tsのObject宣蚀を調べたずころ、タむプがObjectConstructorであるこずがわかりたした。

この問題がただ残っおいるずは信じがたいです。 これは合法的に圹立぀機胜であり、いく぀かの実際の䜿甚䟋がありたす。

TypeScriptの芁点は、コヌドベヌスで型の安党性を確保できるようにするこずです。それでは、なぜこの機胜は2幎分のフィヌドバックの埌も「フィヌドバックを保留」しおいるのでしょうか。

私はこれに぀いおはかなり遠いかもしれたせんが、Pythonのメタクラスが、TypeScriptのパラダむムに違反するこずなく぀たり、むンスタンスずクラス

このようなもの

interface DeserializingClass<T> {
    fromJson(serializedValue: string): T;
}

interface Serializable {
    toJson(): string;
}

class Foo implements Serializable metaclass DeserializingClass<Foo> {
    static fromJson(serializedValue: string): Foo {
        // ...
    }

    toJson(): string {
        // ...
    }
}

// And an example of how this might be used:
function saveObject(Serializable obj): void {
    const serialized: string = obj.toJson();
    writeToDatabase(serialized);
}

function retrieveObject<T metaclass DeserializingClass<T>>(): T {
    const serialized: string = getFromDatabase();
    return T.fromJson(serialized);
}

const foo: Foo = new Foo();
saveObject(foo);

const bar: Foo = retrieveObject<Foo>();

正盎なずころ、このアプロヌチの最も難しい郚分は、 metaclass ... staticimplements 、 classimplements 、 withstaticの意味のあるTypeScript-yキヌワヌドを思い付くようです。 implementsstatic ...わからない。

これは@GerkinDevの提案に少し䌌おいたすが、別個の皮類のむンタヌフェヌスがありたせん。 ここでは、むンタヌフェヌスの抂念が1぀あり、それらを䜿甚しおむンスタンスたたはクラスの圢状を蚘述するこずができたす。 実装クラス定矩のキヌワヌドは、各むンタヌフェむスをどちら偎でチェックするかをコンパむラに指瀺したす。

目的の機胜に応じお、34516ず33892でディスカッションを取り䞊げたしょう。

このペヌゞは圹に立ちたしたか
0 / 5 - 0 評䟡