如何获取从 Class 实例克隆的对象的类型?
How do you get the type of the object that is cloned from a Class Instance?
假设我有这个例子class,但实际上它有更多的属性
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 很智能,当我实例化 class 时,它会给我所有正确的属性:
var classInstance = new Foo('name', new Date().getTime())
classInstance.name // ok
classInstance.dob // ok
classInstance.age // ok
在我的代码中的某个地方,class 使用传播运算符被克隆,我不确定 TS 在幕后做了什么,但它真的很聪明并为我提供了所有正确的属性
var classJSON = {...classInstance};
classJSON.name // ok
classJSON.dob // ok
classJSON.age // missing
这很好,但是我有时需要使用 classJSON
的类型。我认为提取它的唯一方法是这样做:
var classJSON = {...new Foo('', 0)}
type ClassJSONType = typeof classJSON;
有没有办法直接从 Foo
中提取类型而不需要 Javascript 实例化?
目前不可能,因为 TS 类型系统不允许跟踪非自有属性。
有一个 proposal for exactly what you want. This comment 也描述了在不剥离非自有属性的情况下表达 Spread 运算符的可能方法。
免责声明:此 post 是基于 的 mod。固方案,纯TS,无任何JS运行时影响。
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]>;
如果您只想避免初始化 Foo,您可以这样做:
var funRetClassJSON = () => ({ ...Foo.prototype });
type TypeOfClassJSON = ReturnType<typeof funRetClassJSON>;
或
var nullClassJSON = false as any ? null : ({ ...Foo.prototype });
type AltTypeOfClassJSON = NonNullable<typeof nullClassJSON>;
当然,这两个示例仍然会产生一些运行时损失,因为仍然会生成一些 JS。
如果您希望该类型在克隆时保持不变,那么您可能需要使用类型断言。
var classJSON = {...classInstance} as Foo;
这将直接通知 Typescript 对象的类型应该是什么。如果没有此注释,可能无法使用扩展运算符进行类型推断。
假设我有这个例子class,但实际上它有更多的属性
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 很智能,当我实例化 class 时,它会给我所有正确的属性:
var classInstance = new Foo('name', new Date().getTime())
classInstance.name // ok
classInstance.dob // ok
classInstance.age // ok
在我的代码中的某个地方,class 使用传播运算符被克隆,我不确定 TS 在幕后做了什么,但它真的很聪明并为我提供了所有正确的属性
var classJSON = {...classInstance};
classJSON.name // ok
classJSON.dob // ok
classJSON.age // missing
这很好,但是我有时需要使用 classJSON
的类型。我认为提取它的唯一方法是这样做:
var classJSON = {...new Foo('', 0)}
type ClassJSONType = typeof classJSON;
有没有办法直接从 Foo
中提取类型而不需要 Javascript 实例化?
目前不可能,因为 TS 类型系统不允许跟踪非自有属性。 有一个 proposal for exactly what you want. This comment 也描述了在不剥离非自有属性的情况下表达 Spread 运算符的可能方法。
免责声明:此 post 是基于
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]>;
如果您只想避免初始化 Foo,您可以这样做:
var funRetClassJSON = () => ({ ...Foo.prototype });
type TypeOfClassJSON = ReturnType<typeof funRetClassJSON>;
或
var nullClassJSON = false as any ? null : ({ ...Foo.prototype });
type AltTypeOfClassJSON = NonNullable<typeof nullClassJSON>;
当然,这两个示例仍然会产生一些运行时损失,因为仍然会生成一些 JS。
如果您希望该类型在克隆时保持不变,那么您可能需要使用类型断言。
var classJSON = {...classInstance} as Foo;
这将直接通知 Typescript 对象的类型应该是什么。如果没有此注释,可能无法使用扩展运算符进行类型推断。