typescript2.0 - プロパティ名が配列の値であるTypeScriptインターフェースを宣言する方法
ライブラリのために .d.ts ファイルを作成しようとしています。このライブラリには設定オブジェクトがあり、開発者が関数を含む別のオブジェクトを提供でき、その関数が呼び出されてログ記録を行う仕組みになっています。
こんな感じ:
type LogFunction = (message?: any, ...optionalParams: any[]) => void;
interface Logger {
warn: LogFunction;
log: LogFunction;
// several more methods here
}
interface Settings {
logger?: Logger;
}
このインターフェースは、関数のプロパティが warn、log などと名付けられている限り動作します。しかし、この設定オブジェクトでは開発者が他の名前をプロパティや関数に使用するように渡すこともできます。たとえば、呼び出すプロパティ/関数の名前として warn を使用する代わりに、次のようなコードを使って anotherName という名前を呼び出すように指示できます。
const settings = {
logger: { anotherName: function() { .... } },
logLevelMethods: [ "anotherName" ]
}
このタイプの宣言はどのように書けばいいですか?
TS 2.9 がシンボルをプロパティ名として使用するサポートをある程度実装していることは知っていますが、ログオブジェクトのキー名に対して配列の値を関連付ける方法が見つかりません。
見落としているのでしょうか?
ありがとう!
参考までに言うと、私は jquery-mockjax jQuery プラグインのための宣言を書こうとしています。
回答 #1
これを実現するには、ジェネリクスとマップ型を使用する必要があります。Logger を、そのキーのユニオンになる型を受け取るマップ型として定義できます:
type Logger<T extends string | symbol| number > = { [P in T]: LogFunction}
そして、Settings から Logger にタイプを転送することができます
interface Settings<T extends string | symbol| number = "log" | "warn"| "error"> {
logger?: Logger<T>;
logLevelMethods: T[]
}
インスタンスを宣言する際には、通常、型パラメータを指定する必要があります。
const simple: Settings<"log" | "warn"| "error"> = {
logLevelMethods: [], // while this can contain the names, it does not have to unfortunately
logger: {
error: () => {},
warn: () => {},
log: () => {},
}
}
より良い解決策は、設定オブジェクトを作成するのを助ける関数を作ることです。
function createSettings<T extends string | symbol | number >(settings: Settings<T> ){
return settings;
}
const otherSymbol = Symbol("Test");
const settings = createSettings({
logLevelMethods : ["warn", "other", "new", 0, otherSymbol],
logger: {
0 : ()=>{},
// 1 : ()=>{}, // This would be an error
// log: ()=> {}, // Also an error not in the array
warn: ()=> {},
other: () => {},
new: ()=> {},
[otherSymbol]: ()=> {}
}
})
これには、配列とロガーのメンバーが一致するという制約を強制する利点もあります(関数に明示的な引数が渡されない場合に限る)
注: string | symbol | number を使用しました。これは 2.9 でキーの最大許容ドメインだからです。このユニオンのメンバーのいずれかを削除することで、その種のキーのサポートを無効にできます(例えば、数値キーを許可しないように number を削除するなど)。
