Me gustaría almacenar una asignación de cadena -> cadena en un objeto de tipografía y hacer que todas las teclas se asignen a cadenas. Por ejemplo:
var stuff = {};
stuff["a"] = "foo"; // okay
stuff["b"] = "bar"; // okay
stuff["c"] = false; // ERROR! bool != string
¿Hay alguna manera de hacer cumplir que los valores deben ser cadenas (o cualquier tipo ...)?
typescript
Armentage
fuente
fuente
number
también está permitido como un tipo de indexacióntype Keys = 'Acceptable' | 'String' | 'Keys'
tipo de indexación (clave)?Aquí, la interfaz
AgeMap
impone claves como cadenas y valores como números. La palabra clavename
puede ser cualquier identificador y debe usarse para sugerir la sintaxis de su interfaz / tipo.Puede usar una sintaxis similar para exigir que un objeto tenga una clave para cada entrada en un tipo de unión:
¡Por supuesto, también puede hacer que este sea un tipo genérico!
Actualización del 10.10.2018: consulte la respuesta de @ dracstaxi a continuación: ahora hay un tipo integrado
Record
que hace la mayor parte de esto por usted.Actualización 1.2.2020: he eliminado por completo las interfaces de mapeo prefabricadas de mi respuesta. La respuesta de @ dracstaxi los hace totalmente irrelevantes. Si aún desea utilizarlos, consulte el historial de edición.
fuente
x = {}; x[1] = 2;
en Chrome luegoObject.keys(x)
devuelve ["1"] yJSON.stringify(x)
devuelve '{"1": 2}'. Los casos de esquina con typeofNumber
(por ejemplo, Infinity, NaN, 1e300, 999999999999999999999, etc.) se convierten en teclas de cadena. También tenga cuidado de otros casos de esquina para claves de cadena comox[''] = 'empty string';
,x['000'] = 'threezeros';
x[undefined] = 'foo'
.Una actualización rápida: desde Typecript 2.1 hay un tipo incorporado
Record<T, K>
que actúa como un diccionario.Un ejemplo de documentos:
Documentación de TypeScript 2.1 en
Record<T, K>
La única desventaja que veo a usar este sobre
{[key: T]: K}
es que se puede codificar información útil sobre qué tipo de clave que está utilizando en lugar de "clave" por ejemplo, si su objeto sólo tenía las llaves principales que podría hacer alusión a que de esta manera:{[prime: number]: yourType}
.Aquí hay una expresión regular que escribí para ayudar con estas conversiones. Esto solo convertirá casos donde la etiqueta es "clave". Para convertir otras etiquetas, simplemente cambie el primer grupo de captura:
Encontrar:
\{\s*\[(key)\s*(+\s*:\s*(\w+)\s*\]\s*:\s*([^\}]+?)\s*;?\s*\}
Reemplazar:
Record<$2, $3>
fuente
{}
?Record
s (a diferencia de, digamos, JavascriptMap
s) solo proporciona una forma de imponer el contenido de un objeto literal. No puedesnew Record...
y vasconst blah: Record<string, string>;
a compilarconst blah;
.Record
s:const isBroken: Record<"hat" | "teapot" | "cup", boolean> = { hat: false, cup: false, teapot: true };
La respuesta de @Ryan Cavanaugh está totalmente bien y sigue siendo válida. Sin embargo, vale la pena agregar que a partir de Fall'16, cuando podemos afirmar que ES6 es compatible con la mayoría de las plataformas, casi siempre es mejor atenerse a Map siempre que necesite asociar algunos datos con alguna clave.
Cuando escribimos,
let a: { [s: string]: string; }
debemos recordar que después de compilar el mecanografiado no existen datos de tipo, solo se usan para compilar. Y {[s: cadena]: cadena; } se compilará a solo {}.Dicho esto, incluso si escribes algo como:
Esto simplemente no se compilará (incluso para
target es6
, obtendráerror TS1023: An index signature parameter type must be 'string' or 'number'.
Entonces, prácticamente está limitado con una cadena o un número como clave potencial, por lo que no hay una gran sensación de forzar la verificación de tipo aquí, especialmente teniendo en cuenta que cuando js intenta acceder a la clave por número, lo convierte en cadena.
Por lo tanto, es bastante seguro asumir que la mejor práctica es usar Map incluso si las claves son cadenas, por lo que me quedaría con:
fuente
let dict: {[key in TrickyKey]: string} = {}
- dondeTrickyKey
es un tipo literal de cadena (por ejemplo"Foo" | "Bar"
).Map
objetos nativos . Los mapas vienen con una sobrecarga de memoria adicional y (lo que es más importante) deben ser instanciados manualmente a partir de cualquier información almacenada como una cadena JSON. A menudo son muy útiles, pero no solo para obtener tipos de ellos.Definir interfaz
Hacer cumplir la clave para que sea una clave específica de la interfaz de configuración
fuente
Sobre la base de la respuesta de @ shabunc, esto permitiría hacer cumplir la clave o el valor, o ambos, para ser cualquier cosa que desee aplicar.
También debería funcionar usando en
enum
lugar de unatype
definición.fuente