文字列->文字列のマッピングをTypescriptオブジェクトに保存し、すべてのキーが文字列にマップされるようにします。例えば:
var stuff = {};
stuff["a"] = "foo"; // okay
stuff["b"] = "bar"; // okay
stuff["c"] = false; // ERROR! bool != string
値が文字列(または任意のタイプ..)でなければならないことを強制する方法はありますか?
文字列->文字列のマッピングをTypescriptオブジェクトに保存し、すべてのキーが文字列にマップされるようにします。例えば:
var stuff = {};
stuff["a"] = "foo"; // okay
stuff["b"] = "bar"; // okay
stuff["c"] = false; // ERROR! bool != string
値が文字列(または任意のタイプ..)でなければならないことを強制する方法はありますか?
var stuff: { [key: string]: string; } = {};
stuff['a'] = ''; // ok
stuff['a'] = 4; // error
// ... or, if you're using this a lot and don't want to type so much ...
interface StringMap { [key: string]: string; }
var stuff2: StringMap = { };
// same as above
interface AgeMap {
[name: string]: number
}
const friendsAges: AgeMap = {
"Sandy": 34,
"Joe": 28,
"Sarah": 30,
"Michelle": "fifty", // ERROR! Type 'string' is not assignable to type 'number'.
};
ここで、インターフェースAgeMap
はキーを文字列として、値を数値として適用します。キーワードname
は任意の識別子にすることができ、インターフェース/タイプの構文を提案するために使用する必要があります。
同様の構文を使用して、オブジェクトが共用体型のすべてのエントリのキーを持つように強制できます。
type DayOfTheWeek = "sunday" | "monday" | "tuesday" | "wednesday" | "thursday" | "friday" | "saturday";
type ChoresMap = { [day in DayOfTheWeek]: string };
const chores: ChoresMap = { // ERROR! Property 'saturday' is missing in type '...'
"sunday": "do the dishes",
"monday": "walk the dog",
"tuesday": "water the plants",
"wednesday": "take out the trash",
"thursday": "clean your room",
"friday": "mow the lawn",
};
もちろん、これをジェネリック型にすることもできます。
type DayOfTheWeek = "sunday" | "monday" | "tuesday" | "wednesday" | "thursday" | "friday" | "saturday";
type DayOfTheWeekMap<T> = { [day in DayOfTheWeek]: T };
const chores: DayOfTheWeekMap<string> = {
"sunday": "do the dishes",
"monday": "walk the dog",
"tuesday": "water the plants",
"wednesday": "take out the trash",
"thursday": "clean your room",
"friday": "mow the lawn",
"saturday": "relax",
};
const workDays: DayOfTheWeekMap<boolean> = {
"sunday": false,
"monday": true,
"tuesday": true,
"wednesday": true,
"thursday": true,
"friday": true,
"saturday": false,
};
10.10.2018アップデート:
以下の@dracstaxiの回答を確認してください-これのRecord
ほとんどを実行する組み込みタイプがあります。
1.2.2020アップデート: 事前に作成されたマッピングインターフェイスを回答から完全に削除しました。@dracstaxiの答えは、それらを完全に無関係にします。それでも使用したい場合は、編集履歴を確認してください。
クイックアップデート:Typescript 2.1以降Record<T, K>
、辞書のように機能する組み込み型があります。
この場合、次のように宣言できます。
var stuff: Record<string, any> = {};
リテラル型を結合することにより、潜在的なキーを制限/指定することもできます。
var stuff: Record<'a'|'b'|'c', string|boolean> = {};
ドキュメントのレコードタイプを使用した、より一般的な例を次に示します。
// For every properties K of type T, transform it to U
function mapObject<K extends string, T, U>(obj: Record<K, T>, f: (x: T) => U): Record<K, U>
const names = { foo: "hello", bar: "world", baz: "bye" };
const lengths = mapObject(names, s => s.length); // { foo: number, bar: number, baz: number }
TypeScript2.1のドキュメントRecord<T, K>
これを使用する場合の唯一の欠点{[key: T]: K}
は、「キー」の代わりに使用しているキーの種類に関する有用な情報をエンコードできることです。たとえば、オブジェクトにプライムキーしかない場合は、次のようにヒントを得ることができます{[prime: number]: yourType}
。
これらの変換を支援するために私が書いた正規表現は次のとおりです。これは、ラベルが「キー」である場合にのみ変換されます。他のラベルを変換するには、最初のキャプチャグループを変更するだけです。
探す:\{\s*\[(key)\s*(+\s*:\s*(\w+)\s*\]\s*:\s*([^\}]+?)\s*;?\s*\}
交換:Record<$2, $3>
不明なキーに名前を渡してから、タイプを書き込むことができます。
type StuffBody = {
[key: string]: string;
};
これで、タイプチェックで使用できます。
let stuff: StuffBody = {};
ただし、FlowTypeの場合、名前を付ける必要はありません。
type StuffBody = {
[string]: string,
};
@Ryan Cavanaughの答えは完全に大丈夫で、まだ有効です。それでも、ES6が大多数のプラットフォームでサポートされていると主張できるFall'16の時点で、データをキーに関連付ける必要がある場合は常にMapに固執する方がよいことを追加する価値があります。
私たちが書くときlet a: { [s: string]: string; }
、typescriptがコンパイルされた後、型データのようなものはなく、コンパイルにのみ使用されることを覚えておく必要があります。そして{[s:文字列]:文字列; }は{}だけにコンパイルされます。
そうは言っても、次のようなものを書く場合でも、
class TrickyKey {}
let dict: {[key:TrickyKey]: string} = {}
これはコンパイルされません(たとえtarget es6
、error TS1023: An index signature parameter type must be 'string' or 'number'.
したがって、実際には、潜在的なキーとして文字列または数字に制限されているため、ここでタイプチェックを強制する意味はあまりありません。特に、jsが数字でキーにアクセスしようとすると、文字列に変換されることに注意してください。
したがって、キーが文字列であっても、ベストプラクティスはマップを使用することであると想定するのは非常に安全です。したがって、私は次のことに固執します。
let staff: Map<string, string> = new Map();
インターフェイスを定義する
interface Settings {
lang: 'en' | 'da';
welcome: boolean;
}
キーを設定インターフェイスの特定のキーに強制します
private setSettings(key: keyof Settings, value: any) {
// Update settings key
}
実際には、組み込みのユーティリティレコードがあります:
const record: Record<string, string> = {};
record['a'] = 'b';
record[1] = 'c'; // leads to typescript error
record['d'] = 1; // leads to typescript error
@shabuncの答えに基づいて、これにより、キーまたは値のいずれか、あるいは両方を、強制したいものに強制することができます。
type IdentifierKeys = 'my.valid.key.1' | 'my.valid.key.2';
type IdentifierValues = 'my.valid.value.1' | 'my.valid.value.2';
let stuff = new Map<IdentifierKeys, IdentifierValues>();
enum
定義の代わりに使用して動作する必要がありtype
ます。
interface AccountSelectParams {
...
}
const params = { ... };
const tmpParams: { [key in keyof AccountSelectParams]: any } | undefined = {};
for (const key of Object.keys(params)) {
const customKey = (key as keyof typeof params);
if (key in params && params[customKey] && !this.state[customKey]) {
tmpParams[customKey] = params[customKey];
}
}
このコンセプトのアイデアがわかればコメントしてください