2017-04-13 8 views
1

関数を引数として受け取り、memoize関数と同様のmemoize関数を返そうとしています。同じ関数型を返す汎用memoize関数

function memoize<T extends Function, R>(f: T): T { 
    const memory = new Map<string, R>(); 

    const g = (...args: any[]) => { 
    if (!memory.get(args.join())) { memory.set(args.join(), f(...args)); } 
    return memory.get(args.join()); 
    }; 

    return g; // g as T => [ts] Type '(...args: any[]) => R' cannot be converted to type 'T'. 
} 

// const exp: (...args: any[]) => RegExp 
const exp = memoize<(text: string) => RegExp, RegExp>((text: string) => { 
    return new RegExp(text.replace(/[^a-zA-Z0-9\s]/g, ".").replace(/\s+/g, "\\s+"), "ig"); 
}); 

問題は、私はちょうどgを返す場合、EXPの署名が(...args: any[]) => RexExpになることであると私はTであることをグラムを強制しようとした場合、その後、tsは、gはTに割り当て可能ではないと文句を言い。

memoizeに渡された関数の正確な同じ型を持つようにexpするためにfのと同じタイプであることをgを「強制」する方法はありますか?

+1

'args.join()'キーとしては良いではありません:あなたはので、オブジェクトを取る機能のために問題を抱えている、例えば'[{}}。join() 'と' [{{foo:' bar '}]。join() 'は同じ値を返します。 mapキーが厳密な等価を使用するので、 'args'だけをマップキーとして使用すると、非厳密な値が複数回メモされることになります。 – artem

+0

@artemコメントをいただきありがとうございます。あなたは正しいです、それは良い鍵ではありません。マップを使用してツリーを構築すると、より良い解決策になります。 – Waterscroll

答えて

3

これが動作しているようだ:

function memoize<R, T extends (...args: any[]) => R>(f: T): T { 
    const memory = new Map<string, R>(); 

    const g = (...args: any[]) => { 
     if (!memory.get(args.join())) { 
      memory.set(args.join(), f(...args)); 
     } 

     return memory.get(args.join()); 
    }; 

    return g as T; 
} 

const exp = memoize((text: string) => { 
    return new RegExp(text.replace(/[^a-zA-Z0-9\s]/g, ".").replace(/\s+/g, "\\s+"), "ig"); 
}); 

code in playground