【问题标题】:Conditional type for an array to provide eirther an Error or a generic when destructured数组的条件类型,在解构时提供错误或泛型
【发布时间】:2021-07-14 18:20:30
【问题描述】:

在我的 Typescript 项目中,我有一个从函数返回的 Result 类型,其中包含错误或一些数据。它可以是[Error, null][null, Data] 的任何一种形式。例如:

type Result<Data> = [ Error | null, Data | null ]

function randomSuccess(): Result<string> {
    if ( Math.random() > 0.5 ) {
        return [ null, 'success' ]
    else {
        return [ new Error( 'oh no' ), null ]
    }
}

const [ err, result ] = randomSuccess()
if ( err ) {
    .... // can now handle the extracted error and result

我希望 Typescript 检查错误或数据中只有一个不为空。例如:

    ...
        return [ new Error( 'oh no' ), 'success' ]

应该抛出一个错误。

我最初尝试为此编写类型是使用条件类型:

type Result<Data> = null extends Error ? [ null, Data ] : [ Error, null ]

当函数返回错误时,这编译得很好。然而,当返回有效数据时——例如return [ null, 'success' ]——编译器会抱怨:

类型“null”不可分配给类型“错误”

我想我理解编译器错误:在我的类型定义中Error 不是参数,所以null extends Error 将始终为假。但是我不知道从这里去哪里。

如何创建[Error, null][null, Data] 的类型,而不是[Error, Data]

【问题讨论】:

  • 如果有人对此问题有很好的欺骗目标,请在您投票关闭时@ping我,以便我删除下面的答案。我没有找到,但在我看来它很可能就在那里。谢谢。

标签: typescript destructuring conditional-types generic-type-parameters


【解决方案1】:

您正在寻找一个union type,其中联合的部分是代表两种可能状态的两个元组(数组):

type Result<Data> =
    [ null, Data ]      // Success
    |
    [ Error, null ];    // Failure

Result&lt;Data&gt; 可以任一有一种形式或另一种形式,但不能在两个地方都有null,也不能有Error, Data。 (也不能有 2 以外的长度。)

这是一个例子:

type Result<Data> =
    [ null, Data ]      // Success
    |
    [ Error, null ];    // Failure
    
function random(): Result<Date> {
//                        ^^^^−−−− Using `Date` for the `Data` type  argument
//                                just for example
    if (Math.random() < 0.5) {
        // Fail
        return [new Error(), null];
    }
    // Succeed
    return [null, new Date()];
}

const a = random();
if (a[0]) {
    // TypeScript now knows that `a[0]` is an `Error`
    console.log(`Error: ${a[0].message}`);
} else {
    // TypeScript now knows that `a[1]` is a `Date`
    console.log(`Success at ${a[1].toString()}`);
}

Playground link

【讨论】:

  • 谢谢,非常有用!可能是一个单独的问题,但是 Typescript 是否可以在解构数组时执行正确的类型检查,而不是需要 a[0]a[1]
  • @jla - 您可以使用解构,但唯一的问题是类型保护仅适用于您检查的内容。因此,例如,在上面,如果我将 const a= random(); 替换为 const [error, date] = random(); 并将 a[0] 替换为 error 并将 a[1] 替换为 date,那么它都可以工作除了那个 TypeScript不会知道dataelse 分支中绝对不是null。如果你做了if (data) 它会知道(但不会知道error 不是nullelse 分支中)。而...
  • ... 如您所见,在执行if (a[0]) 时,它缩小了a 的类型,因此已知a[1]else 分支中不是-null .我不认为有办法解决这个问题。但是你通常可以构建你的代码,这样你想要的就是缩小的东西。
  • (对不起,date,不是上面的data。)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-08-11
  • 1970-01-01
  • 1970-01-01
  • 2020-11-11
  • 1970-01-01
  • 1970-01-01
  • 2021-12-01
相关资源
最近更新 更多