打字稿泛型-“扩展对象”毫无意义吗?最佳做法是啥?

Posted

技术标签:

【中文标题】打字稿泛型-“扩展对象”毫无意义吗?最佳做法是啥?【英文标题】:Typescript generics - is "extends object" pointless? What is the best practice?打字稿泛型-“扩展对象”毫无意义吗?最佳做法是什么? 【发布时间】:2021-05-02 19:46:30 【问题描述】:

我注意到<P extends object> 泛型通常毫无意义,因为基本上javascript 中的所有内容都是一个对象。大多数文字是具有 .toString 方法的对象。字符串是具有 .length 属性等的对象。我开始更喜欢 <P> 但很好奇其他人注意到了什么。

我现在没有很好的例子,我只是想听听其他人的经验。

【问题讨论】:

我想不出extends object 不会是多余的情况,但我有兴趣学习其他方式。 实际上,string does not extend object,尽管String 确实如此。我投票结束,因为这个问题似乎是基于一个错误的前提。 <P extends any> 也是 tsx 文件的一种解决方法,以防止

被解释为 JSX 标记(尽管可以使用对象而不是任何对象进行映像)。如果没有意义,就不能真正权衡。我想如果P extends object 并且你试图将一个数字作为 P 传递它不会允许它虽然

对于 TSX 解决方法:<P,> 也可以在不引入约束的情况下工作 为了更详细,我注意到 typescript 将字符串解释为对象的情况,然后我拥有此类对象的所有这些不可靠的键 (toString | valueOf | toNumber | ...)。还有@jcalz,感谢您的深入回答!我一直假设object 是相同的,但不知道Object 是一个实际类型 【参考方案1】:

更多信息请参见"The object Type in TypeScript"。

TypeScript 中的 object type 专门用于排除 primitive 七种类型,stringnumberbooleanbigintsymbolundefinednull。 (是的,typeof null === "object" 在运行时,但它在 JS 和 TS 中仍然被认为是原始的)。确实,stringnumberbooleanbigintsymbol 值将自动包装在 StringNumberBooleanBigInt 和 @987654@3 中对象(分别)当您访问它们上的成员时,就好像它们是对象一样。但它们可与真实物体区分开来,有时这会有所不同。 TypeScript 手册中给出的示例是 Object.create(),如果传递原始类型的参数(null 除外),则会导致运行时错误。因此,TypeScript 对Object.create() 的键入指定其参数的类型为object | null。如果您希望您的通用参数排除原语,<P extends object> 将是正确的方法......所以它不是毫无意义的。

请注意,TypeScript 中还有一个Object 接口,以大写的O 开头。该接口包含存在于 JS 中的所有内容上的(明显的)成员,例如 valueOf()toString()。当你说“一切都是对象”时,它可能更接近你的想法;只有nullundefined 不能分配给Object。不过一般来说,you probably don't want to use the Object type in TypeScript;这种包装器类型几乎不是人们想要使用的。

如果你真的想捕捉“任何可以像对象一样被索引的东西”,你可能应该使用所谓的“空对象”类型,。这是一个没有已知属性的对象类型,其行为类似于Object。同样,只有nullundefined 不能分配给。事实上,过去不受约束的泛型类型参数(如<P> 而不是<P extends Q>)被隐式约束为。所以过去写<P extends > 是毫无用处的。

然而,从 TypeScript 3.5 开始,unconstrained generics are now given an implicit constraint of unknown instead of unknown 类型确实是 TypeScript 中的“一切”。您可以为unknown 类型的变量分配任何值(反之亦然)。写<P extends unknown>真的没意义。

我们不妨以any 结尾,这是终极的“无所不能”类型。您不仅可以将任何内容分配给any(例如unknown),还可以将any 分配给任何内容(例如never)。使用any就像举手放弃;它更多的是禁用类型检查,而不是实际类型。 Since TypeScript 3.9,写<P extends any> 与写<P extends unknown> 相同,因此同样没有意义。 (过去,<P extends any> 允许您在 P 未解决时将 P 视为 any,就像在通用函数实现中一样,但这被认为是愚蠢的并已更改。)

Playground link to code

【讨论】:

精彩而周到的回复,详尽地涵盖了询问者感兴趣的整个主题。谢谢!学到的比我正在寻找的要多得多! - 特别喜欢你对any 的定义:-D you can also assign any to anything (like never) 好像不对。 Here is a playground link to code

以上是关于打字稿泛型-“扩展对象”毫无意义吗?最佳做法是啥?的主要内容,如果未能解决你的问题,请参考以下文章

typescript 打字稿泛型示例

typescript 打字稿泛型

打字稿泛型类型 T toString

带有约束的打字稿泛型不能分配给泛型接口

打字稿泛型类参数

难以理解的打字稿泛型函数重载