打字稿泛型-“扩展对象”毫无意义吗?最佳做法是什么?
我注意到<P extends object>泛型通常毫无意义,因为基本上 javascript 中的所有内容都是对象。大多数文字是具有 .toString 方法的对象。字符串是具有 .length 属性等的对象。我开始喜欢<P>但很好奇其他人注意到了什么。
我现在没有一个很好的例子,我更多地只是想听听其他人的经历。
回答
有关更多信息,请参阅“ objectTypeScript 中的类型”。
TypeScript 中的object类型是专门为排除七种基本类型而引入的,string, number, boolean, bigint, symbol, undefined, 和null。(是的,typeof null === "object"在运行时,但它在 JS 和 TS 中仍然被认为是原始的)。这是事实string,number,boolean,bigint,和symbol值将自动包裹String,Number,Boolean,BigInt,和Symbol对象(分别)当您访问他们的成员,如果他们的对象。但它们与真实物体是有区别的,有时这会有所不同。TypeScript 手册中给出的示例是Object.create(),如果传递原始类型的参数(除了null),则会导致运行时错误。因此 TypeScript 的类型 forObject.create()指定它的参数是 type object | null。如果您希望您的泛型参数排除原语,那<P extends object>将是正确的方法......所以它不是毫无意义的。
请注意,ObjectTypeScript 中还有一个接口,以大写O. 此接口包含存在于 JS 中所有内容的(明显)成员,例如valueOf()和toString()。这可能更接近你说“一切都是对象”时的想法;onlynull且undefined不可分配给Object. 不过,一般来说,您可能不想Object在 TypeScript 中使用该类型;这种包装类型几乎不是人们想要使用的。
如果你真的想捕获“任何可以像对象一样被索引的东西”,你应该使用所谓的“空对象”类型,{}. 这是一种没有已知属性的对象类型,其行为类似于Object. 同样, onlynull和undefined不可分配给{}。事实上,过去的情况是不受约束的泛型类型参数(如<P>代替<P extends Q>)被隐式约束为{}。所以过去写<P extends {}>.
然而,从 TypeScript 3.5 开始,不受约束的泛型现在被赋予了一个隐式约束unknown而不是{}。unknown在 TypeScript 中,类型确实是“一切”。您可以为类型的变量分配任何值unknown(但反之则不然)。写起来真的没有意义<P extends unknown>。
我们不妨以any,终极的“随心所欲”类型结束。您不仅可以将任何内容分配给any(例如unknown),还可以分配any给任何内容(例如never)。使用any就像是举手投降;它更多的是禁用类型检查,而不是实际类型。从 TypeScript 3.9 开始,写作<P extends any>与写作相同<P extends unknown>,因此同样毫无意义。(它曾经是<P extends any>允许你把P喜欢any的时候P是没有得到解决,就像在一个通用功能的实现,但是这是愚蠢的考虑和改变。)
Playground 链接到代码