TS系列(6): 有时,对象的属性顺序也很重要

359 阅读3分钟

本篇是**「一起学习** TypeScript **」**系列的第6篇,接下来笔者将持续深耕,不定时更新一系列精彩纷呈的TypeScript文章,旨在解答使用TypeScript过程中的各种疑难杂症,一起探索TS的无穷魅力!

【TS系列回顾】:

TS系列(1): React中能否使子组件实现“类型安全”?

TS系列(2): 使用泛型提升TS函数可重用性

TS系列(3): 什么情况下可以使用any?

TS系列(4): let和const是如何工作的?

TS系列(5): 如何为process.env强化类型?

对象中定义每个属性的顺序会对类型推断有影响么?带着这个疑问,让我们先来看一个简单的例子:

一、例子

假设我们创建一个函数process,它的参数是一个对象:其中包含属性produce和属性consume

我们使用泛型,将produce属性的返回值类型作为consume属性的参数类型

const process = <T>({
    produce:(input: string) => T;
    consume: (t:T) => void;
}) => {
    const value = obj.produce("abc")
    obj.consume(value)
}

现在来使用上面的函数:

二、问题

上面👆🏻的例子看起来一切运转正常,没有任何问题。直到某天,有个同事使用了这个函数,但是它的类型推断不起作用:

output被TS推断为unknown类型!这是为什么呢?

我们可以看到produce函数已经明确地返回一个numbe类型,为何没起作用呢🤔

🔎仔细观察后,我们可以发现同事使用时,将consume定义在了produce之前。难道属性的顺序会有影响么?

在TS4.7的某次PR之后,TS使用参数对象中的属性顺序来推断类型。这是为了修复上下文相关函数中的各种已长期存在的错误(详细可见PR链接中的内容)

这意味着,在某些特定的场景中,你定义属性的顺序对TS类型推断是有影响的! 因此,如果你曾遇到过与属性排序有关的奇怪错误,这就是原因!

三、可以使用 NoInfer解决么?

有人会提出疑问,针对上述属性顺序影响了类型推断的问题,我使用NoInfer来强制TS不对某些目标进行推理,不就可以了么?

NoInfer的主要作用是在泛型编程中阻止类型推断。在TypeScript中,泛型函数能够根据传入的参数自动推断类型,但在某些情况下,这种自动推断可能不符合预期,导致不合法的函数调用被接受,而合法的调用却被拒绝。为了处理这种情况,开发者通常需要添加额外的类型参数来约束函数的行为,确保类型安全。NoInfer允许开发者明确告诉编译器哪些类型不应该被自动推断,从而增强了代码的类型安全性

实际上,使用NoInfer并不能达到想要的效果:

结果仍然是 unknown😅😅

所以,在上述场景下,还是需要注意对象中属性的定义顺序才能达到预期效果!