【问题标题】:How do you get the type of the object that is cloned from a Class Instance?如何获取从类实例克隆的对象的类型?
【发布时间】:2020-06-28 14:33:59
【问题描述】:

假设我有这个示例类,但实际上它有更多属性

class Foo {
  name: string
  dob: number

  constructor(name: string, dob: number) {
    this.name = name;
    this.dob = dob;
  }

  get age() {
     return new Date().getTime() - this.dob
  }
}

现在 Typescript 很智能,当我实例化该类时,它会给我所有正确的属性:

var classInstance = new Foo('name', new Date().getTime())

classInstance.name // ok
classInstance.dob // ok
classInstance.age // ok

在我的代码中某处使用扩展运算符克隆了该类,我不确定 TS 在幕后做了什么,但它真的很聪明,并且为我提供了所有正确的属性

var classJSON = {...classInstance};

classJSON.name // ok
classJSON.dob // ok
classJSON.age // missing

tsplayground

这很好,但是我有时需要使用 classJSON 的类型。我想提取它的唯一方法是这样做:

var classJSON  = {...new Foo('', 0)}
type ClassJSONType = typeof classJSON; 

有没有办法直接从Foo 中提取类型而不需要 Javascript 实例化?

【问题讨论】:

  • “第二类”是什么意思?类实例的形状?如果是这样,那就是Foo
  • 更新更清晰。
  • this 有帮助吗?
  • 我觉得我的问题可以帮助回答那个问题,但标签是 ts2.0... 从那时起发生了很多变化
  • @lonewarrior556 上面链接的答案提供了正确的解决方案。它在 ts3.x 中仍然有效。

标签: typescript typescript3.0


【解决方案1】:

如果你只是想避免初始化 Foo,你可以这样做:

var funRetClassJSON = () => ({ ...Foo.prototype });
type TypeOfClassJSON = ReturnType<typeof funRetClassJSON>;

var nullClassJSON = false as any ? null : ({ ...Foo.prototype });
type AltTypeOfClassJSON = NonNullable<typeof nullClassJSON>;

当然,这两个示例仍然会产生一些运行时损失,因为仍然会生成一些 JS。

【讨论】:

  • 我非常喜欢这个,虽然不是纯 TS,但它确实避免了初始化 Foo ,它实际上有一个复杂的构造函数。
【解决方案2】:

免责声明:这篇文章是基于Matt McCutchen's answer 的模组。这是一个可靠的解决方案,没有任何 JS 运行时影响的纯 TS。

type IfEquals<X, Y, T> =
    (<T>() => T extends X ? 1 : 2) extends
  (<T>() => T extends Y ? 1 : 2) ? T : never;

type JSONify<T> = Pick<T, {
  [P in keyof T]: IfEquals<{ [Q in P]: T[P] }, { -readonly [Q in P]: T[P] }, P>
}[keyof T]>;

上述技巧排除了所有readonly 字段。要进一步排除方法,请使用以下命令:

type JSONify<T> = Pick<T, {
  [P in keyof T]: IfEquals<{ [Q in P]: T[P] extends Function ? never : T[P] }, { -readonly [Q in P]: T[P] }, P>
}[keyof T]>;

Playground

【讨论】:

  • 这个问题可能应该因为重复而被关闭,但是赏金阻止了这个动作,所以我发布了这个。
  • 请注意,此解决方案不能排除继承的方法并排除readonly字段
  • @Shlang 原始答案确实不包括 readonly 字段,至于方法,请参阅我的编辑。
  • 谢谢,但还是有一些限制。请检查此playground
  • @Shlang 现在我明白你的意思了。是的,你是对的,这个解决方案并没有涵盖所有方面。类型系统对对象自身的属性完全视而不见。
【解决方案3】:

目前不可能,因为 TS 类型系统不允许跟踪非自己的属性。 proposal 正是您想要的。 This comment 还描述了在不剥离非自有属性的情况下表达扩展运算符的可能方法。

【讨论】:

    【解决方案4】:

    如果您希望类型在克隆时保持不变,那么您可能需要使用类型断言。

    var classJSON = {...classInstance} as Foo;
    

    这将直接通知 Typescript 对象的类型应该是什么。如果没有此注释,可能无法使用扩展运算符进行类型推断。

    【讨论】:

      猜你喜欢
      • 2012-02-18
      • 2010-11-27
      • 2023-02-16
      • 1970-01-01
      • 2017-05-19
      • 2021-11-20
      • 1970-01-01
      • 2014-01-26
      • 2019-10-23
      相关资源
      最近更新 更多