web-dev-qa-db-ja.com

TypeScriptでGeneric Promiseを宣言して、Generic型が "<void>"の場合、そのメソッドの1つがパラメーターを取らないようにする方法を教えてください。

TypeScriptでは、このようにPromiseのタイプを定義できるようにしたいので、次のようにします。

_//This works today:
new Promise<number>((resolve)=>{
   //Cool
   resolve(5);
   //Error, because I didn't pass a number:
   resolve();
}

//This is what I want to do also:
new Promise<void>((resolve)=>{
   //Error, because I passed a value:
   resolve(5);
   //Cool, because I declared the promise to be of type void, so resolve doesn't take a value:
   resolve();
}
_

私が見たすべてのpromise定義ファイルは、promiseの「解決」メソッドが値を取る必要があることを宣言しています。 ここ は、すばらしいDefinitelyTypedプロジェクトの最近の例です。

_declare class Promise<R> implements Thenable<R> {
    constructor(callback: (resolve : (result: R) => void, reject: (error: any) => void) => void); 
///...
}
_

「」

つまり、「解決コールバックにはタイプRの値を渡す必要があります。」 _new Promise<number>_のようなpromiseはそれで問題ありません。 TypeScriptは、タイプnumberの値でresolveを呼び出していることを確認します。

ただし、値がないプロミスが必要な場合、値を渡さずにresolve()を呼び出せるようにしたい場合はどうすればよいですか?私は次のように自分の約束を宣言できます:_new Promise<void>_しかし、それでもresolveを呼び出して、ある種の値を渡す必要があります。私はresolve(undefined)を呼び出すことができますが、少し奇妙に読みます。

TypeScriptでこの概念を正しくキャプチャする方法はないようです。「このジェネリックの型が 'void'の場合、この関数のパラメーターを期待しないでください。」

私ができる最も近いことは、resolveメソッドで結果をオプションとしてマークすることですが、これは、型付きバージョンの場合でも、結果がalwaysオプションであることを意味します約束。

10
Taytay

mightが満足のいく回避策を考え出したところです。 _Promise<void>_を使用したい場合、resolveコールバックはnotではなく、パラメーターを受け取ります。 resolveメソッドが常にオプションのパラメーターを取るようにすると、次のように新しいクラスを定義できます。

_export class VoidPromise extends RSVP.Promise<void>{
    //Note that resolve does not take a parameter here:
    constructor(callback:(resolve:() => void, reject:(error:any) => void) => void){
        super(callback);
    }
}
_

その場合、次のように使用できます。

_    public static testVoidPromise() : VoidPromise{
        return new VoidPromise((resolve, reject)=>{

            setTimeout(1000, ()=>{
                if (Math.random() < 0.5){
                    //Note that resolve() does NOT take a parameter
                    resolve();
                }else{
                    reject(new Error("Something went wrong"));
                }
            })
        });
    }
_

確かに、開発者は単に「Promise」の代わりにVoidPromiseを使用する必要がありますが、意図した効果は、resolveパラメーターをオプションとして誤ってマークする必要なく達成されます。

私のシナリオでは、上記のコードはallresolveメソッドをオプションの結果としてマークするよりも私の期待に応えています。マークallは、99%の場合、オプションで危険と感じます。常にオプションである場合は、_Promise<number>_を宣言し、結果なしでresolve()を呼び出し、約束に従ってundefined結果を取得できます。その場合、私はその約束を拒否するべきでした。 resolveメソッドのパラメーターが本当にオプションであるとは期待されていません。 (ソース: https://github.com/domenic/promises-unwrapping#the-promise-constructor

2
Taytay

これは機能します!
約束の定義更新済み であり、このようなユースケースをサポートします。

実行可能な例は長すぎて投稿できません。しかし、最新の定義とPromiseコードをエディターにコピーして貼り付けるだけで、サンプルが機能することがわかります。

4
Anders

Promiseインターフェースを使用する方法から、値を渡したい場合もあれば、値を渡さないようにしたい場合もあるので、それがオプションのパラメーターの目的です。 「未定義」の結果でプロミスを解決することが受け入れられない場合(IMOこれは悪い考えではありません。これは、コードで何が起こっているかを正確に伝えます-プロミスの結果is udefined)解決策を提案できますそれはあなたが探しているもののようです:

私は約束の「契約」を定義しますと言いましょう:

export interface IMyPromiseResult {
    result: number;
}

そしてそれを約束とともに使用する:

new Promise<IMyPromiseResult>((resolve)=>{

   resolve(<IMyPromiseResult>{ result: 5 });

   resolve(<IMyPromiseResult>{ });
}

このアプローチはもう少し複雑ですが、いくつかの興味深いオプションが開かれます...一方、現在のDefinitelyTyped Promiseコンストラクターは次のように定義されます。

constructor(callback: (resolve: (result?: R) => void, reject: (error: any) => void) => void);

したがって、オプションの結果を持つことは許可されており、それで問題ありません。

2
Slawek