typescript - Wie man den Typ darauf beschränkt, ein Schlüssel in einem generischen Objekt zu sein, dessen Wert ein String ist
Ich habe ein Interface namens MyInterface, das so aussieht:
interface MyInterface<T, K extends keyof T> {
key: K
data: Array<T>
}
Ich möchte die key-Eigenschaft so einschränken, dass sie nur Schlüssel enthält, die in T vorhanden sind, und auch, dass die Schlüssel in T nur Zeichenketten sind. Das obige Interface schränkt den Schlüssel ein, aber nicht seinen Wert auf nur Zeichenketten. Wie kann ich diese Einschränkung hinzufügen? Einige Beispiele für das Verhalten, das ich suche:
interface Data {
foo: string
bar: number
}
const d: Data[] = [{ foo: 'xxx', bar: 1 }]
// this is valid as the key is in the Data interface and the value of the key is a string
const a: MyInterface<Data, 'foo'> = { key: 'foo', data: d }
// this should be a type error as the value of bar is a number, not a string
const b: MyInterface<Data, 'bar'> = { key: 'bar', data: d }
// this should also be a type error as the key is not in the object
const c: MyInterface<Data, 'baz'> = { key: 'baz', data: d }
Antwort #1
Sie möchten sicherstellen, dass im MyInterface<T, K> der Typ T eine string-Eigenschaft am Schlüssel K hat. Es gibt mehrere Möglichkeiten, dies zu schreiben. Zum Beispiel könnten Sie K auf KeysMatching<T, string> einschränken, wobei KeysMatching in der Antwort auf „In TypeScript, wie erhält man die Schlüssel eines Objekttyps, deren Werte einen bestimmten Typ haben?“ beschrieben ist.
Aber es ist noch einfacher, T auf Record<K, string> zu beschränken (unter Verwendung des Utility-Typs Record<K, V>):
interface MyInterface<T extends Record<K, string>, K extends keyof T> {
key: K
data: Array<T>
}
Dann funktionieren deine Beispiele wie gewünscht:
const a: MyInterface<Data, 'foo'> = { key: 'foo', data: d }; // okay
const b: MyInterface<Data, 'bar'> = { key: 'bar', data: d }; // error!
// ----------------> ~~~~
// Type 'Data' does not satisfy the constraint 'Record<"bar", string>'.
// Types of property 'bar' are incompatible.
const c: MyInterface<Data, 'baz'> = { key: 'baz', data: d }; // error!
// ----------------> ~~~~
// Type 'Data' does not satisfy the constraint 'Record<"baz", string>'.
Playground-Link zum Code
