typescript - ¿Se puede mezclar un tipo literal de cadena y el tipo "string" y usarlos como clave en un tipo mapeado?
Me gustaría definir un tipo mapeado donde las claves 'foo' y 'bar' sean de tipo number y todas las demás claves sean de tipo string
Mi primera intuición fue resolver esto con un tipo condicional de la siguiente manera:
type FooOrBar = 'foo' | 'bar';
type MyMappedType = {
[key in FooOrBar | string]: key extends FooOrBar ? number : string;
}
var x: MyMappedType = {
foo: 1, // Type 'number' is not assignable to type 'string'.(2322)
bar: 2, // Type 'number' is not assignable to type 'string'.(2322)
baz: 'I am a string' // ok!
}
Ejemplo 1
El problema aquí es que TypeScript reduce el alias de tipo FooOrBar | string al tipo string en la clave. Así que, de hecho, TypeScript evalúa este tipo a
type MyMappedType = {
[key in string]: key extends FooOrBar ? number : string;
}
así que la condición key extends FooOrBar siempre es falsa y la definición de tipo es inútil para mi necesidad.
Mi segunda intuición fue usar un tipo de intersección:
type FooOrBar = 'foo' | 'bar';
type MyMappedType = {
[key in FooOrBar]:number;
} & {
[key in string]: string;
};
var x: MyMappedType = { // Type 'number' is not assignable to type 'string'.(2322)
foo: 1,
bar: 2,
baz: 'I am a string'
}
Ejemplo 2
Pero esto tampoco funciona.
¿Existe alguna posibilidad de definir un tipo así en TypeScript?
Respuesta #1
Podrías crear propiedades para cada uno de tus casos de indexación, por ejemplo.
type numberLiterals = 'foo' | 'bar'
type myMappedType = {
numbers: { [key in numberLiterals]: number; };
strings: { [key: string]: string };
}
var x: myMappedType = {
numbers: {
foo: 1,
bar: 2,
// zzz: 5 -> not assignable
},
strings: {
fo: '',
fooo: ''
// baar: 1 -> not assignable
}
}
Patio de recreo
