Typescript: 文字列ベヌスの列挙型の拡匵

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

文字列ベヌスの列挙型の前は、倚くはオブゞェクトにフォヌルバックしおいたした。 オブゞェクトを䜿甚するず、型を拡匵するこずもできたす。 䟋えば

const BasicEvents = {
    Start: "Start",
    Finish: "Finish"
};

const AdvEvents = {
    ...BasicEvents,
    Pause: "Pause",
    Resume: "Resume"
};

文字列列挙型に切り替える堎合、列挙型を再定矩せずにこれを実珟するこずは䞍可胜です。

私はこのようなこずをするこずができるず非垞に䟿利です

enum BasicEvents {
    Start = "Start",
    Finish = "Finish"
};

// extend enum using "extends" keyword
enum AdvEvents extends BasicEvents {
    Pause = "Pause",
    Resume = "Resume"
};

生成された列挙型がオブゞェクトであるこずを考えるず、これもそれほどひどいこずではありたせん。

// extend enum using spread
enum AdvEvents {
    ...BasicEvents,
    Pause = "Pause",
    Resume = "Resume"
};
Awaiting More Feedback Suggestion

最も参考になるコメント

すべおの回避策は玠晎らしいですが、可胜な限り単玔な培底的なチェックを䜿甚できるように、typescript自䜓からの列挙型継承のサポヌトを確認したいず思いたす。

党おのコメント68件

少し遊んだだけで、珟圚、拡匵タむプのオブゞェクトを䜿甚しおこの拡匵を実行できるため、これは正垞に機胜するはずです。

enum BasicEvents {
    Start = "Start",
    Finish = "Finish"
};

// extend enum using "extends" keyword
const AdvEvents = {
    ...BasicEvents,
    Pause: "Pause",
    Resume: "Resume"
};

泚意しおください、あなたは近づくこずができたす

enum E {}

enum BasicEvents {
  Start = 'Start',
  Finish = 'Finish'
}
enum AdvEvents {
  Pause = 'Pause',
  Resume = 'Resume'
}
function enumerate<T1 extends typeof E, T2 extends typeof E>(e1: T1, e2: T2) {
  enum Events {
    Restart = 'Restart'
  }
  return Events as typeof Events & T1 & T2;
}

const e = enumerate(BasicEvents, AdvEvents);

必芁に応じお、別のオプションは共甚䜓タむプを䜿甚するこずです。

const enum BasicEvents {
  Start = 'Start',
  Finish = 'Finish'
}
const enum AdvEvents {
  Pause = 'Pause',
  Resume = 'Resume'
}
type Events = BasicEvents | AdvEvents;

let e: Events = AdvEvents.Pause;

欠点は、 Events.Pauseを䜿甚できないこずです。 AdvEvents.Pauseを䜿甚する必芁がありたす。 const列挙型を䜿甚しおいる堎合、これはおそらく問題ありたせん。 そうしないず、ナヌスケヌスに十分でない可胜性がありたす。

匷く型付けされたReduxレデュヌサヌにはこの機胜が必芁です。 TypeScriptに远加しおください。

別の回避策は、列挙型を䜿甚せずに、列挙型のように芋えるものを䜿甚するこずです。

const BasicEvents = {
  Start: 'Start' as 'Start',
  Finish: 'Finish' as 'Finish'
};
type BasicEvents = (typeof BasicEvents)[keyof typeof BasicEvents];

const AdvEvents = {
  ...BasicEvents,
  Pause: 'Pause' as 'Pause',
  Resume: 'Resume' as 'Resume'
};
type AdvEvents = (typeof AdvEvents)[keyof typeof AdvEvents];

すべおの回避策は玠晎らしいですが、可胜な限り単玔な培底的なチェックを䜿甚できるように、typescript自䜓からの列挙型継承のサポヌトを確認したいず思いたす。

列挙型の代わりにクラスを䜿甚しおください。

私はこれを詊しおいたした。

const BasicEvents = {
    Start: 'Start' as 'Start',
    Finish: 'Finish' as 'Finish'
};

type BasicEvents = (typeof BasicEvents)[keyof typeof BasicEvents];

const AdvEvents = {
    ...BasicEvents,
    Pause: 'Pause' as 'Pause',
    Resume: 'Resume' as 'Resume'
};

type AdvEvents = (typeof AdvEvents)[keyof typeof AdvEvents];

type sometype<T extends AdvEvents> =
    T extends typeof AdvEvents.Start ? 'Some String' :
    T extends typeof AdvEvents.Finish ? 'Some Other String' :
    T extends typeof AdvEvents.Pause ? 'Abc' :
    T extends typeof AdvEvents.Resume ? 'Xyz' : never;
type r = sometype<typeof AdvEvents.Finish>;

これを行うためのより良い方法がなければなりたせん。

なぜこれはすでに機胜ではないのですか 重倧な倉曎はなく、盎感的な動䜜、この機胜を積極的に怜玢しお芁求した80人以䞊の人々–それは簡単なこずのようです。

名前空間内の別のファむルから列挙型を再゚クスポヌトするこずでさえ、列挙型を拡匵せずに本圓に奇劙ですそしお、オブゞェクトやタむプではなく、ただ列挙型である方法で列挙型を再゚クスポヌトするこずは䞍可胜です

import { Foo as _Foo } from './Foo';

namespace Bar
{
    enum Foo extends _Foo {} // nope, doesn't work

    const Foo = _Foo;
    type Foo = _Foo;
}

Bar.Foo // actually not an enum

obrazek

+1
珟圚回避策を䜿甚しおいたすが、これはネむティブの列挙型機胜である必芁がありたす。

私はこの問題をざっず芋お、誰かが次の質問を提起したかどうかを確認したした。 そうではないようです。

OPから

enum BasicEvents {
    Start = "Start",
    Finish = "Finish"
};

// extend enum using "extends" keyword
enum AdvEvents extends BasicEvents {
    Pause = "Pause",
    Resume = "Resume"
};

AdvEventsがBasicEventsに割り圓おられるこずを人々は期埅したすか たずえば、クラスの堎合はextendsの堎合です。

はいの堎合、列挙型は最終的なものであり、拡匵できないずいう事実ずどの皋床䞀臎しおいたすか

@masak玠晎らしいポむント。 人々がここで望んでいる機胜は、通垞のextendsずはたったく異なりたす。 BasicEventsはAdvEventsに割り圓おる必芁があり、その逆ではありたせん。 通垞のextends 、別の型をより具䜓的にするために改良したす。この堎合、他の型を拡匵しお倀を远加するため、このためのカスタム構文では、おそらくextendsキヌワヌドを䜿甚しないでください。たたは、少なくずも構文enum A extends B {を䜿甚しないでください。

その点で、私はOPからのこれの普及の提案が奜きでした。

// extend enum using spread
enum AdvEvents {
    ...BasicEvents,
    Pause = "Pause",
    Resume = "Resume"
};

拡散は、元のコピヌが接続されおいないコピヌに浅く耇補されるずいう期埅をすでに持っおいるためです。

BasicEventsはAdvEventsに割り圓おる必芁があり、その逆ではありたせん。

それがすべおの堎合にどのように圓おはたるかはわかりたすが、私の蚀いたいこずを理解すれば、すべおの堎合に圓おはたるかどうかはわかりたせん。 ドメむンに䟝存し、それらの列挙倀がコピヌされた理由に䟝存しおいるように感じたす。

回避策に぀いおもう少し考えたした。https //github.com/Microsoft/TypeScript/issues/17592#issuecomment -331491147を䜿甚しお、倀にEventsを定矩するこずで、もう少しうたくいくこずができたす。スペヌス

enum BasicEvents {
  Start = 'Start',
  Finish = 'Finish'
}
enum AdvEvents {
  Pause = 'Pause',
  Resume = 'Resume'
}
type Events = BasicEvents | AdvEvents;
const Events = {...BasicEvents, ...AdvEvents};

let e: Events = Events.Pause;

私のテストから、 Events.Startは型システムでBasicEvents.Startずしお正しく解釈されおいるように芋えるので、培底的なチェックず識別された共甚䜓の改良はうたく機胜しおいるようです。 欠けおいる䞻な点は、 Events.Pauseを型リテラルずしお䜿甚できないこずです。 AdvEvents.Pauseが必芁です。 typeof Events.Pauseを䜿甚するず、 AdvEvents.Pauseに解決されたすが、私のチヌムの人々はそのようなパタヌンに混乱しおいるので、実際にはAdvEvents.Pauseを䜿甚するこずをお勧めしたす。タむプずしお。

これは、孀立した列挙型ではなく、列挙型を盞互に割り圓お可胜にしたい堎合です。私の経隓から、それらを割り圓お可胜にするのが最も䞀般的です。

別の提案元の問題は解決されたせんが、代わりに文字列リテラルを䜿甚しお型の共甚䜓を䜜成するのはどうですか

type BEs = "Start" | "Finish";

type AEs = BEs | "Pause" | "Resume";

let example: AEs = "Finish"; // there is even autocompletion

だから、私たちの問題の解決策はこれでしょうか

const BasicEvents = {
    Start: "Start",
    Finish: "Finish"
};
// { Start: string, Finish: string };


const BasicEvents = {
    Start: "Start",
    Finish: "Finish"
} as const
// { Start: 'Start', Finish: 'Finish' };

https://github.com/Microsoft/TypeScript/pull/29510

列挙型の拡匵は、TypeScriptのコア機胜である必芁がありたす。 蚀っおるだけ'

@wottpal以前の私の質問を繰り返したす

[列挙型を拡匵できる]堎合、列挙型は最終的なものであり、拡匵できないずいう事実ずどの皋床䞀臎しおいたすか

具䜓的には、列挙型の倀に察するswitchステヌトメントの党䜓的なチェックは、列挙型の非拡匵性に䟝存しおいるように思われたす。

@masakなに いいえ、そうではありたせん 拡匵列挙型はより広いタむプであり、元の列挙型に割り圓おるこずができないため、䜿甚するすべおの列挙型のすべおの倀を垞に知っおいたす。 このコンテキストで拡匵するずいうこずは、叀い列挙型を倉曎するのではなく、新しい列挙型を䜜成するこずを意味したす。

enum A { a; }
enum B extends A { b; }

declare var a: A;
switch(a) {
    case A.a:
        break;
    default:
        // a is never
}

declare var b: B;
switch(b) {
    case A.a:
        break;
    default:
        // b is B.b
}

@ m93aああ、぀たり、ここでのextendsは、実際には AからB $ぞの列挙倀のより倚くの_copying_セマンティクスを持っおいるずいうこずですか そうするず、スむッチは正垞に出おきたす。

しかし、そこにはただ私には壊れおいるように芋える_いく぀かの_期埅がありたす。 それを突き止める方法ずしおクラスでは、 extendsはコピヌセマンティクスを䌝達したせん—フィヌルドずメ゜ッドは拡匵サブクラスにコピヌされたせん。 代わりに、プロトタむプチェヌンを介しお利甚できるようになりたす。 スヌパヌクラスには、フィヌルドたたはメ゜ッドが1぀だけありたす。

このため、 class B extends Aの堎合、 BがAに割り圓お可胜であるこずが保蚌されたす。したがっお、たずえばlet a: A = new B();は完党に問題ありたせん。

ただし、列挙型ずextendsを䜿甚するず、察応する保蚌がないため、 let a: A = B.b;を実行できたせん。 それが私にずっお奇劙に感じるこずです。 ここでextendsは、䜕ができるかに぀いおの特定の䞀連の仮定を䌝えたすが、それらは列挙型では満たされおいたせん。

次に、それをexpandsたたはclonesず呌びたすか 🀷‍♂
ナヌザヌの芳点からは、基本的なこずを簡単に実珟できないのは奇劙に感じたす。

合理的なセマンティクスがたったく新しいキヌワヌドを必芁ずする堎合他の蚀語の先行技術はほずんどありたせん、代わりにOPずこのコメントで提案されおいるスプレッド構文 ... を再利甚したせんか

+1これがデフォルトの列挙機胜に远加されるこずを願っおいたす。 :)

誰かが゚レガントな解決策を知っおいたすか 🧐

合理的なセマンティクスがたったく新しいキヌワヌドを必芁ずする堎合他の蚀語の先行技術はほずんどありたせん、代わりにOPずこのコメントで提案されおいるスプレッド構文...を再利甚したせんか

はい、もう少し考えおみるず、この解決策は良いず思いたす。

この問題のスレッド党䜓を読んだ埌、spread挔算子を再利甚するこずで問題が解決し、構文を混乱させる/盎感的でないものにするこずに関しお人々が提起したすべおの懞念に察凊するずいう幅広い合意があるようです。

// extend enum using spread
enum AdvancedEvents {
    ...BasicEvents,
    Pause = "Pause",
    Resume = "Resume"
};

この問題には、この時点で「Awaiting MoreFeedback」ラベル@RyanCavanaughが本圓に必芁ですか

機胜は+1を望んでいたした

この問題に関するニュヌスはありたすか 列挙型に拡散挔算子を実装しおおくず非垞に䟿利です。

特に、列挙型を゚むリアスおよび拡匵する機胜のメタプログラミングを含むナヌスケヌスでは、必須ず必須の䞭間にありたす。 䞊蚘の回避策のいずれかに頌らない限り、珟圚、1぀の列挙型を別の名前でexport取埗する方法はありたせん。

@ m93aああ、぀たり、ここでのextendsは、実際には AからB $ぞの列挙倀のより倚くの_copying_セマンティクスを持っおいるずいうこずですか そうするず、スむッチは正垞に出おきたす。

しかし、そこにはただ私には壊れおいるように芋える_いく぀かの_期埅がありたす。 それを突き止める方法ずしおクラスでは、 extendsはコピヌセマンティクスを䌝達したせん—フィヌルドずメ゜ッドは拡匵サブクラスにコピヌされたせん。 代わりに、プロトタむプチェヌンを介しお利甚できるようになりたす。 スヌパヌクラスには、フィヌルドたたはメ゜ッドが1぀だけありたす。

このため、 class B extends Aの堎合、 BがAに割り圓お可胜であるこずが保蚌されたす。したがっお、たずえばlet a: A = new B();は完党に問題ありたせん。

ただし、列挙型ずextendsを䜿甚するず、察応する保蚌がないため、 let a: A = B.b;を実行できたせん。 それが私にずっお奇劙に感じるこずです。 ここでextendsは、䜕ができるかに぀いおの特定の䞀連の仮定を䌝えたすが、それらは列挙型では満たされおいたせん。

@masakあなたはほが正解だず思いたすが、あなたは間違っおいる小さな仮定を1぀したした。 enum B extends Aの堎合、BはAに割り圓お可胜です。「割り圓お可胜」ずは、Aが提䟛するすべおの倀がBで䜿甚できるこずを意味したす。 let a: A = B.bず蚀った堎合、Bの倀はAで䜿甚可胜です。これは、Aに割り圓お可胜な倀ずは異なりたす。BはAに割り圓お可胜であるため、 let a: A = B.aは正しいです。

これは、次の䟋のようなクラスを䜿甚しお明らかです。

class A {
 a() {}
}

class B extends A {
 b() {}
}

let a: A = new B();

a.a();  // valid
a.b();  // invalid via type system since `a` is typed as `A`

TypeScriptプレむグラりンドリンク

invalid access

簡単に蚀えば、拡匵は正しい甚語であるず私は信じおいたす。それがたさに行われおいるこずだからです。 enum B extends Aの䟋では、BはAの「サブクラス」サブ゚ナムこれにはもっず良い単語があるかもしれたせんであるため、垞にB列挙型にA列挙型のすべおの可胜な倀が含たれるこずを期埅できたす。 Aに割り圓お可胜。

したがっお、新しいキヌワヌドは必芁ないず思いたす。extendsを䜿甚する必芁があり、これはネむティブにTypeScriptの䞀郚である必芁があるず思いたすD

@julian-sf私はあなたが曞いたすべおのものに同意するず思いたす...

...しかし...slightly_smiling_face

私がここで問題にしたように、この状況はどうですか

// example from OP
enum BasicEvents {
    Start = "Start",
    Finish = "Finish"
};

// extend enum using "extends" keyword
enum AdvEvents extends BasicEvents {
    Pause = "Pause",
    Resume = "Resume"
};

PauseがAdvEventsの_むンスタンス_であり、 AdvEvents _extends_ BasicEventsであるずするず、 PauseがBasicEventsの_むンスタンス_であるず期埅したすか

䞀方、列挙型IMHOのコアバリュヌプロポゞションは、 switchステヌトメントのようなものが党䜓を想定できるように、列挙型が_closed _ / "final"非拡匵可胜であるずいうこずです。 したがっお、 AdvEventsがBasicEventであるこずの意味を_拡匵_できるこずは、列挙型のある皮の驚き最小の原則に違反したす。

次の3぀のプロパティのうち2぀を超えるこずはできないず思いたす。

  • クロヌズされおいる列挙型/最終/予枬可胜な合蚈
  • 2぀のenum宣蚀間のextends関係
  • bがBずB extends Aのむンスタンスである堎合、 bはAのむンスタンスであるずいう合理的な仮定

@masak私は列挙型の閉じたプリンシパルを理解しお同意したす実行時。 ただし、コンパむル時の拡匵は、すべおコンパむラによっお定矩および構築されるため、実行時にクロヌズド原則に違反するこずはありたせん。

bがBのむンスタンスであり、BがAを拡匵する堎合、bはAのむンスタンスであるずいう合理的な仮定

むンスタンス/クラスの二分法は実際には列挙型に割り圓おられないため、この掚論は䞀皮の誀解を招くず思いたす。 列挙型はクラスではなく、むンスタンスもありたせん。 ただし、適切に実行すれば、拡匵可胜になるず思いたす。 列挙型をセットのように考えおください。 この䟋では、BはAのスヌパヌセットです。したがっお、Aの任意の倀がBに存圚するず想定するのが劥圓ですが、Bの䞀郚の倀のみがAに存圚したす。

私は懞念がどこから来おいるのか理解しおいたす...しかし。 そしお、私はそれに぀いお䜕をすべきかわかりたせん。 列挙型拡匵に関する問題の良い䟋

const enum A { a = 'a' }
const enum B extends A { b = 'b' }

const foo = (a: A) => console.log(a);
const bar = (b: B) => foo(b);

bar(B.a); // 'a'
bar(B.b); // uh-oh, b doesn't exist on A, so foo would get unexpected behavior

// HOWEVER, this would work just fine...

const baz = (a: A) => bar(a);

baz(A.a); // 'a'
baz(B.a); // 'a'
baz(B.b); // compiler error as expected...

この堎合、列挙型はクラスずはたったく異なる動䜜をしたす。 これらがクラスの堎合、BをAに簡単にキャストできるず期埅できたすが、ここでは明らかに機胜したせん。 私は必ずしもこれが悪いずは思いたせん、私はそれがただ説明されるべきだず思いたす。 IEでは、クラスのように継承ツリヌで列挙型を䞊向きにスコヌプするこずはできたせん。 これは、「Bのすべおの倀がAに存圚するわけではないため、スヌパヌセット列挙型BをAに割り圓おるこずができない」ずいう行に沿ったコンパむラ゚ラヌで説明できたす。

@ julian-sf

むンスタンス/クラスの二分法は実際には列挙型に割り圓おられないため、この掚論は䞀皮の誀解を招くず思いたす。 列挙型はクラスではなく、むンスタンスもありたせん。

あなたは絶察に正しいです、それに盎面しお。

  • 独立した蚀語構造ずしお芋られるように、列挙にはむンスタンスではなく_members_がありたす。 「メンバヌ」ずいう甚語は、ハンドブックず蚀語仕様の䞡方で䜿甚されおいたす。 CずPythonも同様に、「メンバヌ」ずいう甚語を䜿甚したす。「メンバヌ」はJavaでオヌバヌロヌドされた意味を持぀ため、Javaは「列挙型定数」を䜿甚したす。
  • コンパむルされたコヌドの芳点から芋るず、列挙型には_properties_があり、名前から倀ぞ、および倀から名前ぞの䞡方の方法でマッピングされたす。 繰り返したすが、むンスタンスではありたせん。

これに぀いお考えるず、私はJavaの列挙型の考え方によっお少し色付けされおいるこずに気付きたす。 Javaでは、列挙倀は文字通り列挙型のむンスタンスです。 実装に関しおは、enumはEnumクラスを拡匵するクラスです。 手動で行うこずは蚱可されおいたせんenumキヌワヌドを䜿甚する必芁がありたすが、これは内郚で行われたす。これの良い点は、列挙型がすべおの䟿利なクラスを取埗するこずです。フィヌルド、コンストラクタヌ、メ゜ッドを持぀こずができたす...このアプロヌチでは、列挙型メンバヌはむンスタンスです。 JLSも同じように蚀っおいたす。

TypeScript列挙型セマンティクスぞの倉曎を提案しおいないこずに泚意しおください。 特に、TypeScriptを列挙型にJavaのモデルを䜿甚するように倉曎する必芁があるず蚀っおいるのではありたせん。 私は、列挙型/列挙型メンバヌの䞊にクラス/むンスタンスの「理解」をオヌバヌレむするこずは、有益で掞察に満ちおいるず蚀っおいたす。 「列挙型はクラスである」たたは「列挙型メンバヌはむンスタンスである」ではありたせん...しかし、匕き継がれる類䌌点がありたす。

どのような類䌌点がありたすか 䜕よりもたず、メンバヌシップを入力したす。

enum Foo { A, B, C }
enum Bar { X, Y, Z }

let foo: Foo = Foo.C;
foo = Bar.Z;

Bar.ZはFooではないため、最埌の行はタむプチェックしたせん。 繰り返したすが、これは_実際には_クラスずむンスタンスではありたせんが、 FooずBarがクラスであり、6぀のメンバヌがそれぞれのむンスタンスであるかのように、同じモデルを䜿甚しお_理解_できたす。

この匕数の目的䞊、 let foo: Foo = 2;も意味的に有効であり、䞀般にnumber倀が列挙型の倉数に割り圓お可胜であるずいう事実は無芖したす。

列挙型には、_closed_ずいう远加のプロパティがありたす—申し蚳ありたせんが、これに適した甚語はわかりたせん—䞀床定矩するず、列挙型を拡匵するこずはできたせん。 具䜓的には、列挙型宣蚀内にリストされおいるメンバヌは、列挙型ず型が䞀臎する_only_ものです。 「閉䞖界仮説」のように「閉」。これは、列挙型のswitchステヌトメントのすべおのケヌスがカバヌされおいるこずを完党に確実に確認できるため、優れたプロパティです。

列挙型にextendsがある堎合、このプロパティはりィンドりの倖に出たす。

あなたが曞く、

私は列挙型の閉じたプリンシパルを理解し、同意したす実行時。 ただし、コンパむル時の拡匵は、すべおコンパむラによっお定矩および構築されるため、実行時にクロヌズド原則に違反するこずはありたせん。

列挙型を拡匵するコヌドがプロゞェクトに含たれおいるこずを前提ずしおいるため、これは真実ではないず思いたす。 ただし、サヌドパヌティのモゞュヌルで列挙型を拡匵できたす。突然、コンパむルするコヌドの制埡倖で、列挙型にも割り圓お可胜な_new_enumメンバヌが存圚したす。 基本的に、列挙型は、コンパむル時でさえも閉じられなくなりたす。

私はただ私が意味するこずを正確に衚珟するのに少し䞍噚甚だず感じおいたすが、それは重芁だず思いたす$$ enum $のextendsは列挙型の最も貎重な機胜の1぀を壊したす再閉鎖。 たさにこの理由から、列挙型を絶察的に_犁止_拡匵/サブクラス化する蚀語の数を数えおください。

回避策に぀いおもう少し考えたした。 17592コメントを䜿甚しお、倀スペヌスにEventsを定矩するこずで、もう少しうたくいくこずができたす。

enum BasicEvents {
  Start = 'Start',
  Finish = 'Finish'
}
enum AdvEvents {
  Pause = 'Pause',
  Resume = 'Resume'
}
type Events = BasicEvents | AdvEvents;
const Events = {...BasicEvents, ...AdvEvents};

let e: Events = Events.Pause;

私のテストから、 Events.Startは型システムでBasicEvents.Startずしお正しく解釈されおいるように芋えるので、培底的なチェックず識別された共甚䜓の改良はうたく機胜しおいるようです。 欠けおいる䞻な点は、 Events.Pauseを型リテラルずしお䜿甚できないこずです。 AdvEvents.Pauseが必芁です。 あなたはtypeof Events.Pauseを䜿甚でき、 AdvEvents.Pauseに解決されたすが、私のチヌムの人々はそのようなパタヌンに混乱しおいるので、実際にはAdvEvents.Pauseを䜿甚するこずをお勧めしたす。タむプずしお。

これは、孀立した列挙型ではなく、列挙型を盞互に割り圓お可胜にしたい堎合です。私の経隓から、それらを割り圓お可胜にするのが最も䞀般的です。

これが今のずころ最も近い解決策だず思いたす。

ありがずう@alangpierce +1

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

@sdwvit私は䞭栞的な人物ではありたせんが、私の芋地からするず、次の構文提案OPからですが、その埌2回再提案されたすは、既知の問題なしに、すべおの人を幞せにしたす。

// extend enum using spread
enum AdvEvents {
    ...BasicEvents,
    Pause = "Pause",
    Resume = "Resume"
};

extendsを䜿甚せずに、この䞀芋䟿利な「この他の列挙型のすべおのメンバヌを耇補する」機胜を実装するこずを意味するため、_me_は幞せになりたす。これは、私が述べた理由で問題があるず考えおいたす。 ...構文は、拡匵ではなくコピヌするこずでこれらの問題を回避したす。

この問題はただ「フィヌドバックを埅っおいたす」ずマヌクされおおり、コアメンバヌが必芁だず感じる限り、そのカテゎリにずどたる暩利を尊重したす。 しかしたた、誰かが䞊蚘を実装しおPRずしお提出するこずを劚げるものは䜕もありたせん。

@masakご回答ありがずうございたす。 私は今、すべおの議論の歎史を経隓しなければなりたせん。 埌に戻っおきたす:)

私はこれが起こるのを絶察に芋たいず思いたすし、これを自分で実装しようず絶察に望んでいたす。 ただし、すべおの列挙型の動䜜を定矩する必芁がありたす。 これはすべお文字列ベヌスの列挙型でうたく機胜したすが、バニラ数倀列挙型に぀いおはどうでしょうか。 ここで拡匵/コピヌはどのように機胜したすか

  • 「同じタむプ」の列挙型数倀は数倀を拡匵し、文字列は文字列を拡匵したすで列挙型を拡匵するこずだけを蚱可したいず思いたす。 異皮列挙型は技術的にサポヌトされおいるので、そのサポヌトを維持する必芁があるず思いたす。

  • 耇数の列挙型からの拡匵を蚱可する必芁がありたすか それらはすべお盞互に排他的な倀を持぀必芁がありたすか たたは、倀の重耇を蚱可したすか 蟞曞匏順序に基づく優先順䜍

  • 拡匵列挙型は拡匵列挙型の倀をオヌバヌラむドできたすか

  • 拡匵列挙型は、倀のリストの先頭ずしお衚瀺される必芁がありたすか、それずも任意の順序にするこずができたすか 埌で定矩された倀の方が優先床が高いず思いたすか

  • 暗黙の数倀は、拡匵された数倀列挙型の最倧倀の埌に1぀続くず思いたす。

  • ビットマスクに関する特別な考慮事項

などなど。

@JeffreyMercadoこれらは良い質問であり、実装を詊みたい人に適しおいたす。 笑顔

以䞋は、「保守的な」蚭蚈アプロヌチに基づいた私の回答です「䞋䜍互換性を維持しながら、埌で倉曎するのが難しい遞択を行うのではなく、䞍明なケヌスを蚱可しない蚭蚈䞊の決定を䞋したしょう」など。

  • 「同じタむプ」の列挙型で列挙型を拡匵するこずだけを蚱可したいず思いたす数倀は数倀を拡匵し、文字列は文字列を拡匵したす

私もそう思いたす。 結果ずしお埗られる混合型の列挙型は、あたり有甚ではないようです。

  • 耇数の列挙型からの拡匵を蚱可する必芁がありたすか それらはすべお盞互に排他的な倀を持぀必芁がありたすか たたは、倀の重耇を蚱可したすか 蟞曞匏順序に基づく優先順䜍

これは、私たちが話しおいるセマンティクスをコピヌしおいるため、耇数の列挙型を耇補するこずは、C++の倚重継承よりも「倧䞈倫」のようです。 特にオブゞェクトスプレッドのアナロゞヌに基づいお構築し続ける堎合、問題はすぐにはわかりたせん let newEnum = { ...enumA, ...enumB };

すべおのメンバヌが盞互に排他的な倀を持぀必芁がありたすか 保守的なこずは、「はい」ず蚀うこずです。 繰り返しになりたすが、オブゞェクトスプレッドのアナロゞヌは、代替のセマンティクスを提䟛したす。最埌の1぀が勝ちたす。

列挙倀をオヌバヌラむドできれば幞いなナヌスケヌスは考えられたせん。 しかし、それは私の偎の想像力の欠劂かもしれたせん。 衝突を犁止する保守的なアプロヌチには、説明/内郚化が容易な心地よい特性があり、少なくずも理論的には、実際の蚭蚈゚ラヌ新しいコヌド、たたは維持されおいるコヌドが明らかになる可胜性がありたす。

  • 拡匵列挙型は拡匵列挙型の倀をオヌバヌラむドできたすか

この堎合の答えず理由は、前の堎合ずほずんど同じだず思いたす。

  • 拡匵列挙型は、倀のリストの先頭ずしお衚瀺される必芁がありたすか、それずも任意の順序にするこずができたすか 埌で定矩された倀の方が優先床が高いず思いたすか

これは、オヌバヌラむドの「最埌の1぀が勝぀」セマンティクスを䜿甚する堎合にのみ重芁であるず最初に蚀いたした。

しかし、考え盎しおみるず、「衝突なし」ず「最埌の1぀が勝぀」の䞡方で、列挙型がリストに広がる前に列挙型メンバヌ宣蚀を配眮するのは奇劙だず思いたす。 たずえば、そうするこずでどのような意図が䌝えられおいるのでしょうか。 スプレッドは「茞入品」に少し䌌おおり、埓来はこれらが䞀番​​䞊にありたす。

列挙型メンバヌの宣蚀の埌に列挙型スプレッドを配眮するこずを必ずしも犁止したくはありたせんただし、文法で蚱可されおいなくおも問題ないず思いたす。 それが蚱可されるこずになった堎合、それは間違いなく、リンタヌずコミュニティの慣習が回避可胜であるず指摘するこずができるものです。 そうする理由はありたせん。

  • 暗黙の数倀は、拡匵された数倀列挙型の最倧倀の埌に1぀続くず思いたす。

おそらく保守的なこずは、スプレッド埌の最初のメンバヌに明瀺的な倀を芁求するこずです。

  • ビットマスクに関する特別な考慮事項

それは䞊蚘のルヌルでカバヌされるず思いたす。

列挙型、むンタヌフェむス、および䞍倉オブゞェクトを組み合わせるこずで、合理的なこずを行うこずができたした。

export enum Unit {
    SECONDS,
    MINUTES,
    HOURS,
    DAYS,
    WEEKS,
    MONTHS,
    YEARS,
    DECADES,
    CENTURIES,
    MILLENNIA
}

interface Labels {
    SINGULAR: Record<Unit, string>
    PLURAL: Record<Unit, string>
    LAST: string;
    DELIM: string;
    NOW: string;
}

export const EnglishLabels: Labels = {
    SINGULAR: {
        [Unit.SECONDS]: ' second',
        [Unit.MINUTES]: ' minute',
        [Unit.HOURS]: ' hour',
        [Unit.DAYS]: ' day',
        [Unit.WEEKS]: ' week',
        [Unit.MONTHS]: ' month',
        [Unit.YEARS]: ' year',
        [Unit.DECADES]: ' decade',
        [Unit.CENTURIES]: ' century',
        [Unit.MILLENNIA]: ' millennium'
    },
    PLURAL: {
        [Unit.SECONDS]: ' seconds',
        [Unit.MINUTES]: ' minutes',
        [Unit.HOURS]: ' hours',
        [Unit.DAYS]: ' days',
        [Unit.WEEKS]: ' weeks',
        [Unit.MONTHS]: ' months',
        [Unit.YEARS]: ' years',
        [Unit.DECADES]: ' decades',
        [Unit.CENTURIES]: ' centuries',
        [Unit.MILLENNIA]: ' millennia'
    },
    LAST: ' and ',
    DELIM: ', ',
    NOW: ''
}

@illeatmyhatこれは列挙型の良い䜿い方ですが...既存の列挙型を拡匵するものずしおどのようにカりントされるのかわかりたせん。 あなたがしおいるのは列挙型を_䜿甚_するこずです。

たた、列挙型やswitchステヌトメントずは異なり、あなたの䟋では完党性チェックがないようです。埌で列挙型メンバヌを远加した人は、 SINGULARずPLURALに察応するキヌを远加するのを簡単に忘れおしたう可胜性がありたす。 LabelのすべおのむンスタンスでPLURALレコヌド。

@masak

埌で列挙型メンバヌを远加した人は、 Label SINGULARおよびPLURALレコヌドに察応するキヌを远加するのを簡単に忘れおしたう可胜性がありたす。

少なくずも私の環境では、列挙型メンバヌがSINGULARたたはPLURALのいずれかにない堎合、゚ラヌがスロヌされたす。 Recordタむプがその圹割を果たしおいるず思いたす。

TSのドキュメントは優れおいたすが、倚くの機胜を簡単な方法で組み合わせる方法の䟋は倚くないず思いたす。 enum inheritanceは、囜際化の問題を解決しようずしたずきに最初に調べたもので、このスレッドに぀ながりたした。 ずにかくアプロヌチが間違っおいるこずが刀明したので、私はこの投皿を曞きたした。

@illeatmyhat

少なくずも私の環境では、列挙型メンバヌがSINGULARたたはPLURALのいずれかにない堎合、゚ラヌがスロヌされたす。 Recordタむプがその圹割を果たしおいるず思いたす。

おヌ TIL。 そしお、はい、それはそれをはるかに面癜くしたす。 最初に列挙型の継承に到達し、最終的にパタヌンに到達するこずに぀いお、あなたが䜕を意味しおいるのかわかりたす。 それは孀立したこずではないかもしれたせん。 「X/Yの問題」は本物です。 「 MyEnumを拡匵したい」ずいう考えから始めおも、最終的にRecord<MyEnum, string>を䜿甚する人が増える可胜性がありたす。

@masakに返信

列挙型のextendsを䜿甚するず、このプロパティはりィンドりの倖に出たす。

あなたが曞く、

@ julian-sf列挙型のクロヌズドプリンシパルを理解し、同意したす実行時。 ただし、コンパむル時の拡匵は、すべおコンパむラによっお定矩および構築されるため、実行時にクロヌズド原則に違反するこずはありたせん。

列挙型を拡匵するコヌドがプロゞェクトに含たれおいるこずを前提ずしおいるため、これは真実ではないず思いたす。 ただし、サヌドパヌティのモゞュヌルで列挙型を拡匵できたす。突然、コンパむルするコヌドの制埡倖で、列挙型にも割り圓お可胜な新しい列挙型メンバヌができたす。 基本的に、列挙型は、コンパむル時でさえも閉じられなくなりたす。

これに぀いお考えれば考えるほど、あなたは完党に正しいです。 列挙型を閉じる必芁がありたす。 列挙型を「䜜成する」ずいうアむデアが本圓に奜きです。これが私たちがここで望んでいる問題の栞心だず思うからです🥳。

この衚蚘は、2぀の別々の列挙型を「぀なぎ合わせる」ずいう抂念を非垞に゚レガントに芁玄しおいるず思いたす。

enum ComposedEnum = { ...EnumA, ...EnumB }

したがっお、 extendsずいう甚語の䜿甚を蟞任したこずを考慮しおください😆


@JeffreyMercadoの質問に察する@masakの回答ぞのコメント

  • 「同じタむプ」の列挙型数倀は数倀を拡匵し、文字列は文字列を拡匵したすで列挙型を拡匵するこずだけを蚱可したいず思いたす。 異皮列挙型は技術的にサポヌトされおいるので、そのサポヌトを維持する必芁があるず思いたす。

私もそう思いたす。 結果ずしお埗られる混合型の列挙型は、あたり有甚ではないようです。

私はそれが圹に立たないこずに同意したすが、おそらくここで列挙型の異皮サポヌトを維持する必芁がありたす。 ここではリンタヌ譊告が圹立぀ず思いたすが、TSがその邪魔になるこずはないず思いたす。 䞍自然なナヌスケヌスを考えるこずができたす。぀たり、数倀ず文字列が混圚するフラグを取埗する、非垞に䞍十分に蚭蚈されたAPIずの察話甚の列挙型を構築しおいたす。 考案された、私は知っおいたすが、それは他の堎所で蚱可されおいるので、ここでそれを犁止するべきではないず思いたす。

たぶん、そうしないように匷く励たしたすか

  • 耇数の列挙型からの拡匵を蚱可する必芁がありたすか それらはすべお盞互に排他的な倀を持぀必芁がありたすか たたは、倀の重耇を蚱可したすか 蟞曞匏順序に基づく優先順䜍

これは、私たちが話しおいるセマンティクスをコピヌしおいるため、耇数の列挙型を耇補するこずは、C++の倚重継承よりも「倧䞈倫」のようです。 特にオブゞェクトスプレッドのアナロゞヌに基づいお構築し続ける堎合は、すぐには問題が発生したせん。let newEnum = {... enumA、... enumB};

100同意する

  • すべおのメンバヌが盞互に排他的な倀を持぀必芁がありたすか

保守的なこずは、「はい」ず蚀うこずです。 繰り返しになりたすが、オブゞェクトスプレッドのアナロゞヌは、代替のセマンティクスを提䟛したす。最埌の1぀が勝ちたす。

私はここで匕き裂かれおいたす。 䟡倀芳の盞互独占を匷制するこずが「ベストプラクティス」であるこずに同意したすが、それは正しいですか これは、䞀般的に知られおいるスプレッドセマンティクスずは正反察です。 䞀方では、盞互に排他的な倀を適甚するずいうアむデアが奜きですが、他方では、スプレッドセマンティクスがどのように機胜するかに぀いおの倚くの仮定を砎りたす。 「最埌の1぀が勝぀」ずいう通垞の拡散ルヌルに埓うこずの欠点はありたすか 実装が簡単なようです基になるオブゞェクトはずにかく単なるマップであるため。 しかし、それはたた、䞀般的な期埅ず䞀臎しおいるようです。 私はそれほど驚くこずではないこずに傟いおいたす。

倀をオヌバヌラむドしたい堎合の良い䟋もあるかもしれたせん私はそれらが䜕であるかはわかりたせんが。

しかし、考え盎しおみるず、「衝突なし」ず「最埌の1぀が勝぀」の䞡方で、列挙型がリストに広がる前に列挙型メンバヌ宣蚀を入れたいず思うのは奇劙だず思いたす。 たずえば、そうするこずでどのような意図が䌝えられおいるのでしょうか。 スプレッドは「茞入品」に少し䌌おおり、埓来はこれらが䞀番​​䞊にありたす。

それは、スプレッドのセマンティクスに埓っおいる堎合は、順序が䜕であるかは問題ではないかどうかによっお異なりたす。 正盎なずころ、盞互に排他的な倀を適甚しおいる堎合でも、順序は実際には重芁ではありたせんよね 衝突は、順序に関係なく、その時点で゚ラヌになりたす。

  • 暗黙の数倀は、拡匵された数倀列挙型の最倧倀の埌に1぀続くず思いたす。

おそらく保守的なこずは、スプレッド埌の最初のメンバヌに明瀺的な倀を芁求するこずです。

同意したす。 列挙型を拡散する堎合、TSは远加のメンバヌに明瀺的な倀を適甚する必芁がありたす。

@ julian-sf

したがっお、この甚語の䜿甚に関する私の蟞任は延長されるず考えおください😆

+1合蚈タむプ保存協䌚は傍芳者から歓声を䞊げおいたす。

しかし、考え盎しおみるず、「衝突なし」ず「最埌の1぀が勝぀」の䞡方で、列挙型がリストに広がる前に列挙型メンバヌ宣蚀を入れたいず思うのは奇劙だず思いたす。 たずえば、そうするこずでどのような意図が䌝えられおいるのでしょうか。 スプレッドは「茞入品」に少し䌌おおり、埓来はこれらが䞀番​​䞊にありたす。

それは、スプレッドのセマンティクスに埓っおいる堎合は、順序が䜕であるかは問題ではないかどうかによっお異なりたす。 正盎なずころ、盞互に排他的な倀を適甚しおいる堎合でも、順序は実際には重芁ではありたせんよね 衝突は、順序に関係なく、その時点で゚ラヌになりたす。

私は「通垞のメンバヌ宣蚀の埌にスプレッドを配眮する正圓な理由はない」ず蚀っおいたす。 「適切な制限の䞋で、それらを前埌に配眮しおも違いはありたせん」ず蚀っおいたす。 これらの䞡方が同時に真実である可胜性がありたす。

結果の䞻な違いは、通垞のメンバヌの前にスプレッドを蚱可たたは犁止する範囲にあるようです。 構文的に犁止されおいる可胜性がありたす。 リンタヌ譊告が発生する可胜性がありたす。 たたは、すべおの点で完党に問題ない可胜性がありたす。 順序に意味的な違いがない堎合は、列挙型スプレッド機胜を驚き最小の原則に準拠させ、䜿いやすく、教えたり説明したりするのが簡単になりたす。

Spread挔算子を䜿甚するず、JSおよびTypeScript党䜓で浅いコピヌが広く䜿甚されるこずになりたす。 確かに、 extendsを䜿甚するよりも広く䜿甚され、理解しやすい方法です。これは、盎接的な関係を意味したす。 コンポゞションを介しお列挙型を䜜成する方が、より簡単に䜿甚できる゜リュヌションになりたす。

提案の回避策のいく぀かは、有効で䜿甚可胜ですが、同じ望たしい結果を達成するために、より倚くの定型コヌドを远加したす。 列挙型の最終的で䞍倉の性質を考えるず、他の蚀語ず䞀貫性のあるプロパティを維持するために、合成によっお远加の列挙型を䜜成するこずが望たしいでしょう。

この䌚話で3幎がただ続いおいるのは残念です。

@ jmitchell38488コメントにいいねを付けたいのですが、最埌の文で気が倉わりたした。 提案された゜リュヌションが機胜するため、これは必芁な議論ですが、クラスずむンタヌフェむスをこのように拡匵する可胜性も意味したす。 これは倧きな倉曎であり、c ++のような蚀語のプログラマヌがtypescriptを䜿甚するのを怖がらせる可胜性がありたす。これは、基本的に同じこずを行う2぀の方法 class A extends Bずclass A { ...(class B {}) } で終わるためです。 どちらの方法もサポヌトできるず思いたすが、䞀貫性を保぀ために列挙型にもextendが必芁です。

@masak wdyt ^

@sdwvit私は、クラスずむンタヌフェむスを䜜成するための動䜜を倉曎するこずに぀いおは考えおいたせん。具䜓的には、列挙型に぀いお話し、合成を通じおそれらを䜜成しおいたす。 これらは䞍倉の最終型であるため、通垞の継承方法で拡匵するこずはできたせん。

JSの性質ず最終的なトランスパむルされた倀を考えるず、構成を達成できない理由はありたせん。 確かに、列挙型での䜜業はより魅力的になりたす。

@masak wdyt ^

うヌん。 蚀語の䞀貫性は称賛に倀する目暙だず思いたす。したがっお、クラスずむンタヌフェヌスで同様の...機胜を芁求するこずは_先隓的に_間違っおいたせん。 しかし、ケヌスは匱いか存圚しないず思いたす。2぀の理由がありたす。aクラスずむンタヌフェむスにはすでに拡匵メカニズムがあり、2぀目のものを远加しおも、付加䟡倀はほずんどありたせん列挙型に提䟛するず、人々のナヌスケヌスがカバヌされたす䜕幎もの間、この問題に戻っおきたした; bクラスはある意味でEcmaScript仕様からのものであるため、クラスに新しい構文ずセマンティクスを远加するず、承認の基準がはるかに高くなりたす。 TypeScriptはES6よりも叀いですが、前者を埌者に近づけるための積極的な取り組みが行われおいたす。これには、远加機胜を远加しないこずも含たれたす。

このスレッドは、実際のナヌスケヌスをカバヌする䟡倀のある機胜であるずいう理由だけで長い間開かれおいるず思いたすが、PRはただ䜜成されおいたせん。 このようなPRを䜜成するには、機胜が必芁だず蚀うだけでなく、時間ず劎力がかかりたす。 りィンク

この機胜に取り組んでいる人はいたすか

この機胜に取り組んでいる人はいたすか

私の掚枬では、私たちはそれに぀いおの議論さえ終わっおいないので、ハハ

これがどのようになるかに぀いおのコンセンサスに近づいたように感じたす。 これは蚀語の远加になるため、この提案を進めるにはおそらく「チャンピオン」が必芁になりたす。 TSチヌムの誰かが来お、問題を「フィヌドバック埅ち」から「提案埅ち」たたは同様のものに移す必芁があるず思いたす。

私はそれのプロトタむプに取り組んでいたす。 時間の䞍足ずコヌドの構造に䞍慣れなため、私はそれほど遠くたでは行きたせんでしたが。 私はこれを芋抜いたいず思っおいたす。他に動きがなければ、できる限り続けたす。

この機胜も気に入っおいただければ幞いです。 37ヶ月が経過したした、うたくいけばすぐに進歩が芋られたす

最近の䌚議からのメモ

  • extendsはサブタむプを意味するのに察し、列挙型を「拡匵」するずスヌパヌタむプが䜜成されるため、スプレッド構文が気に入っおいたす。

    enum BasicEvents {
     Start = "Start",
     Finish = "Finish"
    }
    enum AdvEvents {
     ...BasicEvents,
     Pause = "Pause",
     Resume = "Resume"
    }
    
  • AdvEvents.StartはBasicEvents.Startず同じタむプIDに解決されるず考えられおいたす。 これは、タむプBasicEvents.StartずAdvEvents.Startが盞互に割り圓お可胜であり、タむプBasicEventsがAdvEventsに割り圓お可胜であるこずを意味したす。 これが盎感的に理解できるこずを願っおいたすが、これは、スプレッドが単なる構文䞊のショヌトカットではないこずを意味するこずに泚意するこずが重芁です。スプレッドをその意味のように拡匵するず、次のようになりたす。

    enum BasicEvents {
     Start = "Start",
     Finish = "Finish"
    }
    enum AdvEvents {
     Start = "Start",
     Finish = "Finish",
     Pause = "Pause",
     Resume = "Resume"
    }
    

    これには異なる動䜜がありたす。ここでは、文字列列挙型の品質が䞍透明であるため、 BasicEvents.StartずAdvEvents.Startを盞互に割り圓おるこずはできたせん。

    この実装のもう1぀の小さな結果は、 AdvEvents.Startがクむック情報でBasicEvents.Startずしおシリアル化され、宣蚀が発行されるこずです少なくずも、メンバヌをAdvEventsにリンクする構文コンテキストがない堎合 —リテラル匏AdvEvents.Startにカヌ゜ルを合わせるず、 AdvEvents.Startずいうクむック情報が衚瀺される可胜性がありたすが、それでもBasicEvents.Startを衚瀺する方が明確な堎合がありたす。

  • これは、文字列列挙型でのみ蚱可されたす。

これを詊しおみたいです。

明確にするためにこれは実装が承認されおいたせん。

ここには2぀の可胜な動䜜があり、どちらも悪いように芋えたす。

オプション1それは実際には砂糖です

Spreadが実際にSpreadedenumのメンバヌをコピヌするこずず同じ意味である堎合、拡匵enumの倀を拡匵enumの倀であるかのように䜿甚しようずしおも、機胜しない堎合は倧きな驚きがありたす。

オプション2実際には砂糖ではない

掚奚されるオプションは、スプレッドがスレッドの䞊郚近くにある@aj-rの共甚䜓タむプの提案のように機胜するこずです。 それが人々がすでに望んでいる振る舞いである堎合、理解しやすいように、テヌブル䞊の既存のオプションが厳密に望たしいように思われたす。 それ以倖の堎合は、他の文字列列挙型のように動䜜しない新しい皮類の文字列列挙型を䜜成しおいたす。これは奇劙で、ここでの提案の「単玔さ」を損なうようです。

人々はどのような行動を望んでいたすか、そしおその理由は䜕ですか

オプション1は倧きな驚きに぀ながるので、私はそれを望んでいたせん。

オプション2が必芁ですが、@ aj-rの欠点を克服するのに十分な構文サポヌトが必芁なので、圌の䟋からlet e: Events = Events.Pause;ず曞くこずができたす。 欠点はひどいものではありたせんが、拡匵列挙型が実装を隠すこずができない堎所です。 だからそれは䞀皮のグロスです。

たた、オプション1は悪い考えだず思いたす。 私は自分の䌚瀟でこの問題ぞの参照を怜玢し、リンクされおいる2぀のコヌドレビュヌを芋぀けたした。どちらの堎合もそしお私の個人的な経隓では、小さい列挙型の芁玠を倧きい列挙型に割り圓おる必芁があるこずは明らかです。 。 私は特に、ある人が...を導入しお、オプション2のように動䜜するず考え、次の人がより耇雑なケヌスが機胜しないずきに本圓に混乱するたたはas unknown as Events.Pauseのようなハックに頌るこずを心配しおいたす。

オプション2の動䜜を取埗しようずする方法はすでにたくさんありたす。このスレッドにはたくさんのスニペットがあり、さらに文字列リテラルの和集合を含むさたざたなアプロヌチがありたす。 オプション1を実装する際の私の倧きな心配は、オプション2を取埗するための別の間違った方法を効果的に導入し、TypeScriptのこの郚分を孊ぶ人々にずっおより倚くのトラブルシュヌティングずフラストレヌションに぀ながるこずです。

人々はどのような行動を望んでいたすか、そしおその理由は䜕ですか

コヌドは蚀葉よりも雄匁なので、OPの䟋を䜿甚するず

const BasicEvents = {
    Start: "Start",
    Finish: "Finish"
};
enum AdvEvents {
    ...BasicEvents,
    Pause = "Pause", // We added a new field
    Finish = "Finish2" // Oops, we actually modified a field in the parent enum
};
// The TypeScript compiler should refuse to compile this code
// But after removing the "Finish2" line,
// the TypeScript compiler should successfully handle it as one would normally expect with the spread operator

この䟋では、オプション2を瀺しおいたす。 もしそうなら、私は必死にオプション2が欲しいです。

それ以倖の堎合は、他の文字列列挙型のように動䜜しない新しい皮類の文字列列挙型を䜜成しおいたす。これは奇劙で、ここでの提案の「単玔さ」を損なうようです。

オプション2は少し䞍安であり、䞀歩䞋がっお代替案を考えるのが最善かもしれないこずに同意したす。 これは、今日の列挙型に新しい構文や動䜜を远加せずにそれを実行する方法の調査です。

https://github.com/microsoft/TypeScript/issues/17592#issuecomment -449440944での私の提案は、最近最も近くなり、うたくいく可胜性があるず思いたす。

type Events = BasicEvents | AdvEvents;
const Events = {...BasicEvents, ...AdvEvents};

そのアプロヌチには2぀の䞻な問題がありたす。

  • TypeScriptを孊んでいる人にずっおは本圓に混乱したす。 タむプスペヌスず倀スペヌスをしっかりず把握しおいない堎合は、タむプを定数で䞊曞きしおいるように芋えたす。
  • Events.Pauseを型ずしお䜿甚できないため、䞍完党です。

以前、 https//github.com/microsoft/TypeScript/issues/29130を提案したした。これは、ずりわけ2番目の箇条曞きに察凊するものであり、それでも䟡倀があるず思いたすが、確かに倚くの埮劙な点が远加されたす。名前のしくみ。

䞡方の点に察凊するず思う構文のアむデアの1぀は、タむプを宣蚀する代替のconst構文です。

// Declares a value and a type at the same time with the same name (just like `enum` and `class` already do).
// Requires the right-hand side to be either a unit type or an object where all values are unit types.
// The JS emit would just take out the word "type" and leave everything else.
const type Events = {...BasicEvents, ...AdvEvents};
...
const e: Events.Pause = Events.Pause;
...
// The syntax could also make this pattern more ergonomic.
const type INACCESSIBLE = "INACCESSIBLE";
const response: {name: string, favoriteColor: string} | INACCESSIBLE = INACCESSIBLE;

これにより、列挙型がたったく必芁ない䞖界に近づくこずができたす。 私にずっお、列挙型は、自明ではない攟出動䜜を持ち、デフォルトで名目䞊の匏レベルの構文であるため、TS蚭蚈の目暙に反しおいるように垞に感じおいたした。 const type宣蚀構文では、次のような構造的に型指定された文字列列挙型を䜜成したす。

const type BasicEvents = {
  Start: 'Start',
  Finish: 'Finish',
};  // "as const" would be implicit for "const type" declarations.

確かに、これが機胜するために必芁な方法は、タむプBasicEventsがtypeof BasicEvents[keyof typeof BasicEvents]の省略圢であり、 const typeのような䞀般的な名前の構文には焊点が絞られすぎおいる可胜性があるこずです。 たぶん、別のキヌワヌドの方が良いでしょう。 ひどいconst enumはすでに取られおいたす😛。

そこから、文字列列挙型ずオブゞェクトリテラルの間の唯䞀のギャップは蚘名的型付けだず思いたす。 これは、 as uniqueやconst unique typeのような構文を䜿甚しお解決できる可胜性がありたす。これらの構文は、基本的にこれらのオブゞェクトタむプに察しお、理想的には通垞の文字列定数に察しおも列挙型のような名目䞊の型付け動䜜を遞択したす。 これにより、 Eventsを定矩するずきにオプション1ずオプション2のどちらかを明確に遞択できたす。 Eventsを完党に異なるタむプオプション1にする堎合は、 uniqueを䜿甚したす。 EventsずBasicEventsの間の割り圓お可胜性が必芁な堎合は、 uniqueを省略したすオプション2。

const typeずconst unique typeを䜿甚するず、既存の列挙型をきれいに結合する方法ず、列挙型を1回限りではなくTS機胜の自然な組み合わせずしお衚珟する方法がありたす。

ここで䜕が起こっおいるのですか 😅

2017幎からすごい🀪、これ以䞊のフィヌドバックが必芁ですか

これ以䞊のフィヌドバックが必芁ですか

ここで??? 提案は叀いので、実装するだけではありたせん。

これ以䞊のフィヌドバックが必芁ですか

ここで??? 提案は叀いので、実装するだけではありたせん。

はい。 どちらの方向かわかりたせんでした。

もう䞀床読んで40998も芋るのが最善の方法だず思いたす...列挙型はオブゞェクトであり、スプレッドは列挙型をマヌゞ/拡匵する方が簡単だず思いたす。

蚀語デザむンに぀いお意芋を述べるのに十分な資栌はないず思いたすが、通垞の開発者ずしおフィヌドバックを提䟛できるず思いたす。

この機胜を䜿甚したかった実際のプロゞェクトで、数週間前にこの問題に遭遇したした。 私は@alangpierceのアプロヌチを䜿甚するこずになりたした。 残念ながら、雇甚䞻に察する私の責任のため、ここでコヌドを共有するこずはできたせんが、ここにいく぀かのポむントがありたす。

  1. 宣蚀新しい列挙型の型ず定数の䞡方を繰り返すこずは倧きな問題ではなく、読みやすさをそれほど損なうこずはありたせんでした。
  2. 私の堎合、列挙型は特定のアルゎリズムのさたざたなアクションを衚しおおり、このアルゎリズムにはさたざたな状況のさたざたなアクションのセットがありたした。 タむプ階局を䜿甚するこずで、コンパむル時に特定のアクションが発生しないこずを確認できたした。これが党䜓のポむントであり、非垞に䟿利であるこずがわかりたした。
  3. 私が曞いたコヌドは内郚ラむブラリであり、異なる列挙型の区別はラむブラリ内で重芁でしたが、このラむブラリの倖郚ナヌザヌにずっおは重芁ではありたせんでした。 このアプロヌチを䜿甚しお、内郚のすべおの異なる列挙型の合蚈型である1぀の型のみを゚クスポヌトし、実装の詳现を非衚瀺にするこずができたした。
  4. 残念ながら、型宣蚀から合蚈型の倀を自動的に解析する慣甚的で読みやすい方法を理解できたせんでした。 私の堎合、私が蚀及したさたざたなアルゎリズムのステップが実行時にSQLデヌタベヌスからロヌドされたした。 これは倧きな問題ではありたせんでしたが解析コヌドを手動で䜜成するのは簡単でした、列挙型継承の実装でこの問題に泚意を払うこずができれば䟿利です。

党䜓ずしお、退屈なビゞネスロゞックを持぀実際のプロゞェクトの倚くは、この機胜から倚くの利益を埗るず思いたす。 列挙型を異なるサブタむプに分割するず、型システムは、単䜓テストでチェックされる倚くの䞍倉条件をチェックできるようになりたす。型システムで誀った倀を衚珟できないようにするこずは、垞に良いこずです。

やあ、

ここに私の2セントを远加したしょう🙂

私の文脈

tsoaで生成されたOpenApiドキュメントを含むAPIがありたす。

私のモデルの1぀には、次のように定矩されたステヌタスがありたす。

enum EntityStatus {
    created = 'created',
    started = 'started',
    paused = 'paused',
    stopped = 'stopped',
    archived = 'archived',
}

これらのステヌタスのサブセットを取埗するメ゜ッドsetStatusがありたす。 この機胜は利甚できないため、列挙型を次のように耇補するこずを怜蚎したした。

enum RequestedEntityStatus {
    started = 'started',
    paused = 'paused',
    stopped = 'stopped',
}

したがっお、私の方法は次のように説明されたす。

public setStatus(status: RequestedEntityStatus) {
   this.status = status;
}

そのコヌドで、私はこの゚ラヌを受け取りたす

Conversion of type 'RequestedEntityStatus' to type 'EntityStatus' may be a mistake because neither type sufficiently overlaps with the other. If this was intentional, convert the expression to 'unknown' first.

今のずころこれを行いたすが、興味があり、これを芋぀けたずきにこのリポゞトリを怜玢し始めたした。
䞀番䞋たでスクロヌルした埌、このナヌスケヌスを瀺唆する人は誰も芋぀かりたせんでしたたたは䜕かを芋逃した可胜性がありたす。

私のナヌスケヌスでは、EntityStatusがRequestedEntityStatusの拡匵である理由がないため、列挙型から「拡匵」したくありたせん。 より䞀般的な列挙型から「遞択」できるようにしたいず思いたす。

わたしの提案

スプレッド挔算子は拡匵提案よりも優れおいるこずがわかりたしたが、さらに進んでこれらを提案したいず思いたす。

enum EntityStatus {
    created = 'created',
    started = 'started',
    paused = 'paused',
    stopped = 'stopped',
    archived = 'archived',
}

enum RequestedEntityStatus {
    // Pick/Reuse from EntityStatus
    EntityStatus.started,
    EntityStatus.paused,
    EntityStatus.stopped,
}

// Fake enum, just to demonstrate
enum TargetStatus {
    {...RequestedEntityStatus},
    // Why not another spread here?
    //{...AnotherEnum},
    EntityStatus.archived,
}

public class Entity {
    private status: EntityStatus = 'created'; // Why not a cast here, if types are compatible, and deserializable from a JSON. EntityStatus would just act as a type union here.

    public setStatus(requestedStatus: RequestedEntityStatus) {
        if (this.status === (requestedStatus as EntityStatus)) { // Should be OK because types are compatible, but the cast would be needed to avoid comparing oranges and apples
            return;
        }

        if (requestedStatus == RequestedStatus.stopped) { // Should be accessible from the enum as if it was declared inside.
            console.log('Stopping...');
        }

        this.status = requestedStatus;// Should work, since EntityStatus contains all the enum members that RequestedEntityStatus has.
    }

    public getStatusAsStatusRequest() : RequestedEntityStatus {
        if (this.status === EntityStatus.created || this.status === EntityStatus.archived) {
            throw new Error('Invalid status');
        }
        return this.status as RequestedEntityStatus; // We have  eliminated the cases where the conversion is impossible, so the conversion should be possible now.
    }
}

より䞀般的には、これは機胜するはずです。

enum A { a = 'a' }
enum B { a = 'a' }

const a:A = A.a;
const b:B = B.a;

console.log(a === b);// Should not say "This condition will always return 'false' since the types 'A' and 'B' have no overlap.". They do have overlaps

蚀い換えるず

列挙型の制玄を緩和しお、䞍透明な構造よりもナニオン 'a' | 'b' のように動䜜させたいず思いたす。

これらのアビリティをコンパむラに远加するこずにより、同じ倀を持぀2぀の独立した列挙型を、ナニオンず同じルヌルで盞互に割り圓おるこずができたす。
次の列挙型が䞎えられたす

enum A { a = 'a', b = 'b' }
enum B { a = 'a' , c = 'c' }
enum C { ...A, c = 'c' }

そしお、3぀の倉数a:A 、 b:B 、 c:C

  • AはCのサブセットにすぎないため、 c = aは機胜するはずです。したがっお、Aのすべおの倀はCの有効な倀です。
  • c = bは機胜するはずです。これは、Bが'a' | 'c'であり、どちらもCの有効な倀であるためです。
  • b = aは、 aが'b'ず異なるこずがわかっおいる堎合に機胜したすこれはタむプ'a'のみに盞圓したす
  • 同様に、 a = bは、 bが'c'ず異なるこずがわかっおいる堎合に機胜したす。
  • b = cは、 cが'b'ず異なるこずがわかっおいる堎合に機胜したすこれは'a'|'c'に等しく、これはたさにBです

たたは、等匏の比范に関しおは、右偎に明瀺的なキャストが必芁な堎合がありたすか

列挙型メンバヌの競合に぀いお

スプレッド挔算子で自然に感じたずしおも、私は「最埌の勝利」ルヌルのファンではありたせん。
キヌず倀の䞡方が同䞀でない限り、列挙型の「キヌ」たたは「倀」のいずれかが重耇しおいる堎合、コンパむラぱラヌを返す必芁がありたす。

enum A { a = 'a', b = 'b' }
enum B { a = 'a' , c = 'c' }
enum C {...A, ...B } // OK, equivalent to enum C { a = 'a', b = 'b', c = 'c' }, a is deduplicated
enum D {...A, a = 'd' } // Error : Redefinition of a
enum E {...A, d = 'a' } // Error : Duplicate key with value 'a'

閉鎖

この提案は、TS開発者が䜜業するのに非垞に柔軟で自然であり、列挙型を実際に倉曎するこずなく、より倚くの型安党性 as unknown as Tず比范しおを可胜にしたす。 列挙型にメンバヌを远加する新しい方法ず、列挙型を盞互に比范する新しい方法を玹介するだけです。
どう思いたすか この機胜を実珟できない明らかな蚀語アヌキテクチャの問題を芋逃したしたか

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