TypeScript:如何声明记录或记录数组的类型?

Posted

技术标签:

【中文标题】TypeScript:如何声明记录或记录数组的类型?【英文标题】:TypeScript: How to declare type for Record or Array of Records? 【发布时间】:2021-06-07 07:52:59 【问题描述】:

假设有一个apiCall 函数返回一个promise,它解析为具有data 属性的对象,该属性可以是RecordRecords 的数组(如Axios)。 我正在尝试适当地声明类型,但出现错误。

这是我声明类型的方式:

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,
    );

但是当我这样使用它时:

(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);
)();

我收到以下错误:

键入'记录 | Record[]' 不可分配给类型 '[key: string]: any;[] |空值'。类型 'Record' 缺少类型 '[key: string]: any;[]' 中的以下属性:length、pop、push、concat 和另外 26 个。

我认为这可能与被视为 Record

的数组有关

【问题讨论】:

【参考方案1】:

这是因为:

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

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

记录数组可分配给记录,但反之亦然。

但是让我们回到你的例子:

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>[]
    

)();

借助重载,我们可以给编译器一些提示。

请看这个部分:// without LET bindings

编译器能够计算出函数的返回类型

【讨论】:

重载是这种特定情况的一种方法(其中返回类型的差异由布尔参数决定)但在一个非最小示例中(如 axios 调用的用例中所述)显式重载签名并不那么简单(因为response.data 的类型是由传递给axios 的methodurl 定义的) 尝试与 axios 分享示例。不知道你的例子没那么简单) 顺便说一句,您可以随时使用Array.isArray。它就像 TS 中的 typeguard

以上是关于TypeScript:如何声明记录或记录数组的类型?的主要内容,如果未能解决你的问题,请参考以下文章

Typescript:如何声明一种值等于对象键的数组类型?

TypeScript 中关联对象数组的接口

TypeScript:如何在编译时声明固定大小的数组以进行类型检查

在 Typescript 中,如何声明一个返回字符串类型数组的函数?

TypeScript从零到一学习记录(三:函数)

涵盖数组和类型化数组的 TypeScript 接口