Búsqueda de sitios web

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

Artículos relacionados