Estoy tratando de usar el siguiente patrón:
enum Option {
ONE = 'one',
TWO = 'two',
THREE = 'three'
}
interface OptionRequirement {
someBool: boolean;
someString: string;
}
interface OptionRequirements {
[key: Option]: OptionRequirement;
}
Esto me parece muy sencillo, sin embargo, aparece el siguiente error:
Un tipo de parámetro de firma de índice no puede ser un tipo de unión. En su lugar, considere usar un tipo de objeto mapeado.
¿Qué estoy haciendo mal?
javascript
typescript
john maccarthy
fuente
fuente
key
solo puede ser cadena, número o símbolo. enum no lo es.Respuestas:
Puede usar el operador TS "in" y hacer esto:
enum Options { ONE = 'one', TWO = 'two', THREE = 'three', } interface OptionRequirement { someBool: boolean; someString: string; } type OptionRequirements = { [key in Options]: OptionRequirement; // Note that "key in". }
fuente
interface OptionRequirements
atype OptionRequirements
La solución más sencilla es utilizar
Record
También puede implementarlo usted mismo como:
type OptionRequirements = { [key in Options]: OptionRequirement; }
Esta construcción solo está disponible para
type
, pero nointerface
.El problema en su definición es decir que la clave de su interfaz debe ser de tipo
Options
, dondeOptions
es una enumeración, no una cadena, número o símbolo.Los
key in Options
medios "para las claves específicas que están en el tipo de unión Opciones".type
alias es más flexible y poderoso queinterface
.Si no tiene que ser utilizado en la clase de su tipo, elija
type
másinterface
.fuente
Tuve un problema similar, pero mi caso fue con otra propiedad de campo en la interfaz, por lo que mi solución es un ejemplo con la propiedad de campo opcional con una enumeración para las claves:
export enum ACTION_INSTANCE_KEY { cat = 'cat', dog = 'dog', cow = 'cow', book = 'book' } type ActionInstances = { [key in ACTION_INSTANCE_KEY]?: number; // cat id/dog id/cow id/ etc // <== optional }; export interface EventAnalyticsAction extends ActionInstances { // <== need to be extended marker: EVENT_ANALYTIC_ACTION_TYPE; // <== if you wanna add another field to interface }
fuente
En lugar de usar una interfaz, use un tipo de objeto mapeado
enum Option { ONE = 'one', TWO = 'two', THREE = 'three' } type OptionKeys = keyof typeof Option; interface OptionRequirement { someBool: boolean; someString: string; } type OptionRequirements = { // note type, not interface [key in OptionKeys]: OptionRequirement; // key in }
fuente
En mi caso, necesitaba que las propiedades fueran opcionales, así que creé este tipo genérico.
type PartialRecord<K extends string | number | symbol, T> = { [P in K]?: T; };
Entonces úsalo como tal:
type MyTypes = 'TYPE_A' | 'TYPE_B' | 'TYPE_C'; interface IContent { name: string; age: number; } interface IExample { type: string; partials: PartialRecord<MyTypes, IContent>; }
Ejemplo
const example : IExample = { type: 'some-type', partials: { TYPE_A : { name: 'name', age: 30 }, TYPE_C : { name: 'another name', age: 50 } } }
fuente
Tuve un problema similar. Estaba tratando de usar solo claves específicas al crear validadores de forma angular.
export enum FormErrorEnum { unknown = 'unknown', customError = 'customError', } export type FormError = keyof typeof FormErrorEnum;
Y el uso:
static customFunction(param: number, param2: string): ValidatorFn { return (control: AbstractControl): { [key: FormErrorEnum]?: any } => { return { customError: {param, param2} }; }; }
Esto permitirá que se utilicen de 1 a X teclas.
fuente