为什么动态对象可以有效地设置为打字稿中的 class

Why is a dynamic object valid to set to a class in typescript

我玩了一点打字稿,发现了这个:

class Greeter {
  e: number;

  p: boolean = true;
}

const xxx = new Greeter(); // true
console.log(xxx instanceof Greeter);
const xxx2: Greeter = { e: 1, p: true }; // <--- 1. why is this valid?
console.log(xxx2 instanceof Greeter); // false

const xxx3: Greeter = Object.setPrototypeOf({ e2: 1 }, Greeter.prototype); // <-- 2. no warning?
console.log(xxx2 instanceof Greeter); // true

所以我的问题是:

  1. 为什么在打字稿中将动态对象分配给 class 对象是有效的,而不是真正的 class。好像不是真的class。以后会改善吗?

  2. 似乎是黑客攻击。但是这些类型没有干净的 Typescript 函数。这应该更干净,有没有更好的检查功能?

我使用带有严格选项的 Typescript 2.4.2。

因为打字稿只进行编译时检查。

如果您使用下面的 link 并粘贴您的代码并获得 JavaScript

const xxx2: Greeter = { e: 1, p: true }; 

converts to -->

var xxx2 = { e: 1, p: true }; 

这只是一个对象,对 class 一无所知 Greeter

https://www.typescriptlang.org/play/index.html

Why is it valid in typescript to assign a dynamic object to a class-object, without being the class for real. It seems not to be the real class.

TypeScript 是一种结构语言,而不是名义语言。这意味着检查结构,并且可以使用任何兼容的类型。一旦您开始依赖此语言功能,名义打字就会让您抓狂。

Will this improved in the future?

无法改进!结构类型岩石 :).

但我想正确的答案是 "no - this is by design"。

const xxx3: Greeter = Object.setPrototypeOf({ e2: 1 }, Greeter.prototype); seems to be the hack. But there are no clean Typescript function for the types. This should be cleaner, is there a better checked function?

这个需要一点解构。

第一部分是TypeScript中有一个动态类型:any。任何具有 any 类型的东西都像变形器。它可以是任意类型。

只要您希望编译器不妨碍并允许您使用动态类型,就可以使用 any。 (在 "the type can change dynamically" 中是动态的,我注意到您将对象文字描述为 dynamic - 但我在这里谈论的是官方动态类型)。

当您调用 Object.setPrototypeOf(...) 时,它 returns 这些特殊动态类型之一,类型为 any.

这意味着,当您将它分配给类型为 Greeter 的变量时,这是允许的,因为您有一个 any 类型。

虽然这可能会让您尝试做某事感到沮丧,但我相信您想要实现的目标是可能的 - 所以请随时询问如何实现您需要做的任何事情,我相信我们'我会想办法帮助

从你的 related Github issue 那里得到的。

@Fenton的正确 is laudable evangelism for structural typing as supported in TypeScript. For those occasions where one finds oneself entertaining thoughts of the forbidden fruit of nominal typing,不过,确实有变通办法:

我建议给 Greeter 一个 private member 这样你就不能再给它分配对象字面量了。私有 class 成员似乎是 "standard" TypeScript 标称类型的解决方法。

示例:

class Greeter {
  private _nominal = true; // add something like this
  e: number;
  p: boolean = true;
}

const xxx = new Greeter();
const xxx2: Greeter = { e: 1, p: true }; // error, missing _nominal
const xxx3: Greeter = { e: 1, p: true, _nominal: true }; // error, _nominal is private

这对你有用吗?这至少会让搬起石头砸自己的脚更难,虽然如果你真的尝试,你会成功:

// don't do this
const xxx4: Greeter = function() { return "ha ha fooled you";} as any as Greeter; 

希望对您有所帮助;祝你好运!