我正在尝试只让我的后代暴露一些祖先的属性。我试图通过实现Pick
export class Base {
public a;
public b;
public c;
}
export class PartialDescendant extends Pick<Base, 'a' |'b'> {
public y;
}
Run Code Online (Sandbox Code Playgroud)
但我收到两个错误-
错误:TS2693:“ Pick”仅引用一种类型,但在此处被用作值。
和
错误:TS4020:导出类“ PartialDescendant”的“ extends”子句具有或正在使用私有名称“ Pick”。
我做错什么了吗,还有另一种方法只公开基类的选定属性吗?
见下面的3.0解决方案
Pick只是一个类型而不是一个类,一个类既是一个类型又是一个对象构造函数。类型仅在编译时存在,这就是为什么会出现错误的原因。
您可以创建一个接受构造函数的函数,并返回一个新的构造函数,该实例将实例化具有较少字段的对象(或至少声明它确实具有该对象):
export class Base {
public c: number = 0;
constructor(public a: number, public b: number) {
}
}
function pickConstructor<T extends { new (...args: any[]) : any, prototype: any }>(ctor: T)
: <TKeys extends keyof InstanceType<T>>(...keys: TKeys[]) => ReplaceInstanceType<T, Pick<InstanceType<T>, TKeys>> & { [P in keyof Omit<T, 'prototype'>] : T[P] } {
return function (keys: string) { return ctor as any };
}
export class PartialDescendant extends pickConstructor(Base)("a", "b") {
public constructor(a: number, b: number) {
super(a, b)
}
}
var r = new PartialDescendant(0,1);
type IsValidArg<T> = T extends object ? keyof T extends never ? false : true : true;
type ReplaceInstanceType<T, TNewInstance> = T extends new (a: infer A, b: infer B, c: infer C, d: infer D, e: infer E, f: infer F, g: infer G, h: infer H, i: infer I, j: infer J) => infer R ? (
IsValidArg<J> extends true ? new (a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J) => TNewInstance :
IsValidArg<I> extends true ? new (a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I) => TNewInstance :
IsValidArg<H> extends true ? new (a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H) => TNewInstance :
IsValidArg<G> extends true ? new (a: A, b: B, c: C, d: D, e: E, f: F, g: G) => TNewInstance :
IsValidArg<F> extends true ? new (a: A, b: B, c: C, d: D, e: E, f: F) => TNewInstance :
IsValidArg<E> extends true ? new (a: A, b: B, c: C, d: D, e: E) => TNewInstance :
IsValidArg<D> extends true ? new (a: A, b: B, c: C, d: D) => TNewInstance :
IsValidArg<C> extends true ? new (a: A, b: B, c: C) => TNewInstance :
IsValidArg<B> extends true ? new (a: A, b: B) => TNewInstance :
IsValidArg<A> extends true ? new (a: A) => TNewInstance :
new () => TNewInstance
) : never
Run Code Online (Sandbox Code Playgroud)
对于构造函数参数,您将放宽参数名称,可选参数和多个签名之类的内容。
编辑
自从原始问题得到回答以来,打字稿已改善了该问题的可能解决方案。通过在剩余参数和扩展表达式中添加元组,我们现在不需要具有所有的重载ReplaceReturnType:
export class Base {
public c: number = 0;
constructor(public a: number, public b: number) {
}
}
type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>
function pickConstructor<T extends { new (...args: any[]) : any, prototype: any }>(ctor: T)
: <TKeys extends keyof InstanceType<T>>(...keys: TKeys[]) => ReplaceInstanceType<T, Pick<InstanceType<T>, TKeys>> & { [P in keyof Omit<T, 'prototype'>] : T[P] } {
return function (keys: string| symbol | number) { return ctor as any };
}
export class PartialDescendant extends pickConstructor(Base)("a", "b") {
public constructor(a: number, b: number) {
super(a, b)
}
}
var r = new PartialDescendant(0,1);
type ArgumentTypes<T> = T extends (... args: infer U ) => any ? U: never;
type ReplaceInstanceType<T, TNewInstance> = T extends new (...args: any[])=> infer R ? new (...a: ArgumentTypes<T>) => TNewInstance : never;
Run Code Online (Sandbox Code Playgroud)
这不仅更短,而且解决了许多问题
| 归档时间: |
|
| 查看次数: |
20901 次 |
| 最近记录: |