Typescript: 建议:object原始类型

创建于 2015-01-26  ·  17评论  ·  资料来源: microsoft/TypeScript

object基本类型

该建议描述了打字稿object的新原始类型。

用例

JavaScript核心api包含一些将object作为参数的函数:

  • Object.getPrototypeOf
  • Object.getOwnPropertyDescriptor
  • Object.create
  • ...等等

当前,打字稿中没有办法阻止将其他原始类型( stringnumber等)传递给那些函数。
例如, Object.create('string')是一个完全有效的打字稿语句,即使最终会出现错误。
创建一个新的object基本类型将允许更正确地为那些函数的签名以及共享相似约束的每个函数建模。

类型检查

可分配性

object类型等于{}减去其他基本类型的可分配性,这意味着:

  • 其他任何基本类型均不可分配给object
  • 任何非基本类型均可分配给object
  • 对象只能分配给{}any

此行为与javascript的工作方式一致,类型表示尊重约束typeof value === 'object'加上undefined每个值。

防护罩

必须为objecttypeof value === 'object'引入一种新型防护。
可选地,编译器还可以接受与Object函数强制转换的比较: Object(value) === value

Suggestion help wanted

最有用的评论

为此提案+1。 我不会将WeakMap视为“专家” API,但我认为仅凭其理由就足以实现此目的。 由于运行时区分对象类型和原始类型,因此只有在TypeScript中具有一种设施也可以进行区分。

该提议还将解决在每个属性都是可选的情况下键入“对象包”的问题,但是不应允许其他原始类型。

所有17条评论

列出一些除Object.函数之外的API会很有用,这会从中受益。

在javascript核心api中,除了Object之外,也许只有某些es6构造会从中受益(WeakMap,Proxy等)。
但是例如每个下划线集合函数也将获得更好的输入,像React这样的框架使用'setState'方法仅接受对象或null ,ImmutableJS,Mori等。

编辑:下划线集合可用于任何类型

在建议审核会议上讨论。 所有这些都是有道理的,但是我们需要用它可以提供的错误数量/丰富的描述来证明新的原始类型的复杂性。 基本上,有更多无法在原语上运行的API的示例,尤其是那些不是“专家” API的API(例如,代理)

发布更多的参考而不是推荐:wink:

interface String { _primitiveBrand?: string; }
interface Boolean { _primitiveBrand?: boolean; }
interface Number { _primitiveBrand?: number; }

interface ObjectOnly {  _primitiveBrand?: void; }

function fn(x: ObjectOnly) { }

// Error
fn(43);
// Error
fn('foo');
// OK
fn({});
// OK
fn(window);

为此提案+1。 我不会将WeakMap视为“专家” API,但我认为仅凭其理由就足以实现此目的。 由于运行时区分对象类型和原始类型,因此只有在TypeScript中具有一种设施也可以进行区分。

该提议还将解决在每个属性都是可选的情况下键入“对象包”的问题,但是不应允许其他原始类型。

Object.observe需要一个非原始目标: http :

我认为标题有点混乱,因为它提到了“原始”一词。 也可以将其称为_“ ECMAScript对象类型” _或_“运行时对象类型” _。 可以从除原始类型(包括undefined类型和符号),函数或构造函数类型以外的任何内容中分配该值。 合法的object类型的条件应基于以下防护措施:

let isObject (x) => typeof x === "object";

根据MDN ,这是typeof的输出:

未定义:“未定义”
Null :“对象”(请参见下文)
布尔值:“布尔值”
编号:“编号”
字符串:“字符串”
符号(ECMAScript 2015中的新增功能) :“符号”
宿主对象(由JS环境提供) :与实现有关
功能对象(以ECMA-262术语实现[[Call]]) :“功能”
任何其他对象:“对象”

没有这种类型,就无法正确匹配上述防护的精确类型,甚至不能作为用户定义的防护。 这对于必须严格使用具有属性并允许for in循环并调用Object原型的对象的函数,以及实现诸如T extends object类的通用约束也很重要。然后安全地引用属性或使用原型函数。

但是,在某些情况下,将函数和构造函数排除在外会有些限制,因此可能会有另一种类型也将其包括在内,并称为_“非原始对象类型” _。 一个局部的解决方法可能是工会object | Function尽管将需要强制转换或其他警卫来正确处理它。

接受公关。 这似乎是一个普遍的问题。 对于任何敢于写interface object { ... }人来说,这都是一个巨大的变化。 实施应简单明了,并遵循上述规则。

旁注:我们都想知道

@RyanCavanaugh工作

大。 我想在TS1.8中使用此类型。

我还希望看到类似object类型的东西。 但是,我质疑它是否应该符合typeof value === 'object' ,因为这将排除函数。 相反,在我看来,预期的object类型应该反映对象语言类型,其中包括函数。 这有几个原因:

  • 据我所知,始终接受纯对象的API也接受函数。
  • 函数Object构造函数继承。

我会按顺序整理这些。

蜜蜂

仅接受对象的API(例如WeakMap接受对象语言类型,而不仅仅是普通对象。 可以的:

function theAnswer() {}

let map = new WeakMap();

map.set(theAnswer, 42);
console.log(map.get(theAnswer)); // 42

对于自定义API和内置API都是如此。 如果我希望有一个对象,通常只需要一堆属性。 函数只是可调用的属性包。

遗产

由于Function扩展了Object构造函数,因此我们也可以在函数上使用Object上的静态方法和实例方法。 例如,以下是可能的:

class DeepThought {
  static getAnswer() {
    return 42;
  }
}

let computer = Object.create(DeepThought);

console.log(computer.getAnswer()); // 42
console.log(Object.getPrototypeOf(computer)); // [Function: DeepThought]

尽管上面的示例有点愚蠢,但它仅说明了内部使用Object方法的API也可以接受函数。

因此,我建议object类型符合以下内容,该类型对应于Object语言类型(除了它包括null ,但在TypeScript中无法防止null任何状况之下)。

function isObject(value) {
  return typeof value === 'object' || typeof value === 'function';
}

用例

我有一个名为Deep Map的项目,该项目可通过嵌套对象的键值对进行递归并沿途转换原始值。 因此,它区分原始类型和非原始类型。 我必须定义一个自定义NonPrimitive接口,如下所示:

interface NonPrimitive {
  [key: string]: any;
  [index: number]: any;
}

export class DeepMap {
  // ...
  private mapObject(obj: NonPrimitive): NonPrimitive { /* ... */ }
}

这不是我第一次定义NonPrimitive接口。 如果我能做到这一点,那就太好了:

export class DeepMap {
  // ...
  private mapObject(obj: object): object { /* ... */ }
}

正如我上面建议的,我并不在乎obj参数是否可调用。 重要的是它是Object _language type_的类型,即它是一堆属性,我可以迭代其键值对。

我同意函数是object s。 目的是排除基元。

好的,我认为这一定是意图。 我只是以为也许我在typeof value === 'object'所有谈话中都错过了一些东西。

这个object类型会允许临时属性分配(例如any )吗? 例如:

const foo: object = {};

foo.bar = 'baz';

没有

之间的实际区别是什么

export class DeepMap {
  // ...
  private mapObject(obj: object): object { /* ... */ }
}

export class DeepMap {
  // ...
  private mapObject(obj: Object): Object { /* ... */ }
}

? (使用objectObject )。 在我看来, FunctionObject Function扩展而来的,所以我不明白为什么我们不能这样做。 你可以解释吗?

@trusktr nullundefined以外的所有值都可以分配给Object类型; 接受Object的函数将采用字符串,数字,布尔值或符号。 只有非原始值可分配给object ; 传递字符串等将产生编译时错误。 object类型在我们期望一个非原始值但不关心其属性是什么的情况下很有用。

此页面是否有帮助?
0 / 5 - 0 等级