【问题标题】:How can I check that an object has at least one record?如何检查一个对象是否至少有一条记录?
【发布时间】:2021-08-28 13:36:56
【问题描述】:

我有以下 TS 代码:

type FunctionMap = Record<
  string,
  (...params: any) => any
>

function needsARecordOfFunctions(functions: FunctionMap) {
  /* ... */
}

needsARecordOfFunctions({ myFunc: 'foobar' }); // Type 'string' is not assignable to type '(...params: any) => any'.
needsARecordOfFunctions(); // Expected 1 arguments, but got 0.
needsARecordOfFunctions({ myFunc: () => {} }); // ✅

// This passes but I want it to fail
needsARecordOfFunctions({});

我的问题是,我怎样才能让needsARecordOfFunctions({}) 因上述代码中的类型错误而失败?我想定义一种记录类型,它至少定义了一条记录。

Playground

【问题讨论】:

  • 您的问题源于{} 在许多情况下不被视为空对象,而是被视为非常广泛的“任何事情发生”类型。确保参数中不允许空对象是棘手的。首先,您需要让编译器推断出使用泛型类型参数传入的参数的确切类型
  • 通常,您可以使用keyof {}never 的观察结果,但是由于Record 实用程序类型带来的索引签名,您的情况很复杂。您首先需要一个用于删除索引的实用程序。见这里:stackoverflow.com/q/51465182/11407695
  • 然后您可以检查生成的泛型类型参数的keyof 是否为never,如下所示:tsplay.dev/Wzyb3m。稍后我将起草一份详细解释步骤的答案

标签: typescript


【解决方案1】:

首先,您需要摆脱索引签名,因为索引签名会影响类型的形状:

keyof { [x:string]: any }; // string | number

Credit 用于通用实用程序类型转到Mihail,我只将其调整为 TS 4.1+。它的要点是,如果stringkeyof T 的子类型,则意味着该类型具有string 索引签名(检查number 得到我们的数字签名):

type RemoveIndex<T> = {
  [ P in keyof T as string extends P ? never : number extends P ? never : P ] : T[P]
};

接下来,您需要让编译器推断传递给要处理的参数的参数的类型。因此,您需要一个通用函数签名,在您的情况下,单个参数限制为 FunctionMap

最后,您必须确保推断的类型通过“无空对象”约束。这可以通过应用keyof {}never 的观察来实现(有关详细信息,请参阅this Q&A)。因此,有条件的keyof RemoveIndex&lt;T&gt; extends never ? never : T 确保此类空对象类型不可分配(类似示例请参见this Q&A):

function needsARecordOfFunctions<T extends FunctionMap>(functions: keyof RemoveIndex<T> extends never ? never : T) { /* ... */ }

将所有这些结合在一起:

needsARecordOfFunctions({ myFunc: 'foobar' }); // Type 'string' is not assignable to type 'never'
needsARecordOfFunctions(); // Expected 1 arguments, but got 0.
needsARecordOfFunctions({ myFunc: () => {}, func2: () => 42 }); // ✅
needsARecordOfFunctions({}); // error, expected

Playground

【讨论】:

    猜你喜欢
    • 2023-03-19
    • 2013-09-27
    • 2018-03-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-09-22
    • 2022-06-17
    • 1970-01-01
    相关资源
    最近更新 更多