Búsqueda de sitios web

TypeScript: ¿Cómo declarar un tipo para un Registro o un Arreglo de Registros?


Supongamos que hay una función apiCall que devuelve una promesa que se resuelve como un objeto que tiene una propiedad data, que puede ser un Record o un arreglo de Records (como Axios). Estoy intentando declarar los tipos apropiadamente, pero estoy recibiendo un error.

Aquí está cómo declaro mis tipos:

type ApiResponseType = {
    data: Record<string, any>[] | Record<string, any>;
};

function apiCall(asArr: boolean): Promise<ApiResponseType> {
    const d = {
        foo: 'bar',
    };
    return Promise.resolve({
        data: asArr ? [d] : d,
    });
}

Pero cuando lo uso así:

(async()=>{
    let a: {[key: string]: any} | null = null;
    let b: {[key: string]: any}[] | null = null;
    a = (await apiCall(false)).data;
    b = (await apiCall(true)).data; // Type 'Record<string, any> | Record<string, any>[]' is not assignable to type '{[key: string]: any;}[] | null'. Type 'Record<string, any>' is missing the following properties from type '{[key: string]: any;}[]': length, pop, push, concat, and 26 more.
    console.log({a, b});
})();

Recibo el siguiente error:

El tipo 'Record | Record[]' no se puede asignar al tipo '{[key: string]: any;}[] | null'. Al tipo 'Record' le faltan las siguientes propiedades del tipo '{[key: string]: any;}[]': length, pop, push, concat, y 26 más.

Creo que puede tener algo que ver con que el arreglo se trate como un Record<string, any>

Respuesta #1

Esto se debe a:

declare var a: Record<string, any>[]
declare var b: Record<string, any>

a = b // error
b = a // ok

Un arreglo de registros se puede asignar a un registro, pero no viceversa.

Pero volvamos a tu ejemplo:

type Data = Record<string, any>[] | Record<string, any>;
type Nullable<T> = T | null

type ApiResponseType<T extends Data> = {
    data: T
};

function apiCall(asArr: true): Promise<ApiResponseType<Record<string, any>[]>>
function apiCall(asArr: false): Promise<ApiResponseType<Record<string, any>>>
function apiCall(asArr: boolean) {
    const d = {
        foo: 'bar',
    };
    return Promise.resolve<ApiResponseType<Data>>({
        data: asArr ? [d] : d,
    });
}
type O = ReturnType<typeof apiCall>

(async () => {
    let a: Nullable<Record<string, any>> = null;
    let b: Nullable<Record<string, any>[]> = null;
    a = (await apiCall(false)).data;
    b = (await apiCall(true)).data;

    // without LET bindings
    {
        const a = (await apiCall(false)).data; // Record<string, any>
        const b = (await apiCall(true)).data; //Record<string, any>[]
    }

})();

Con la ayuda de las sobrecargas, podemos darle alguna pista al compilador.

Por favor vea esta sección:// sin enlaces LET

El compilador puede determinar el tipo de retorno de la función