首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >‘Pick<’仅指类型,但在试图扩展Pick<时用作值

‘Pick<’仅指类型,但在试图扩展Pick<时用作值
EN

Stack Overflow用户
提问于 2018-03-22 13:26:18
回答 2查看 78.8K关注 0票数 18

我只想让祖先的某些属性暴露在我的后代身上。我试图通过Pick来实现它

代码语言:javascript
复制
export class Base {
    public a;
    public b;
    public c;
}

export class PartialDescendant extends Pick<Base, 'a' |'b'> {
   public y;
}

但我收到两个错误-

错误: TS2693:'Pick‘只指类型,但在这里被用作值。

错误: is 4020:“扩展”导出类'PartialDescendant‘的子句已经或正在使用私有名称'Pick’。

我是不是做错了什么,还有其他方法只公开基类的选定属性吗?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2018-03-22 13:39:22

参见下面的3.0解决方案

Pick只是一个类型,它不是一个类,类既是一个类型,也是一个对象构造函数。类型只存在于编译时,这就是获得错误的原因。

您可以创建一个接受构造函数的函数,并返回一个新的构造函数,该构造函数将实例化一个具有较少字段的对象(或至少声明它实例化):

代码语言:javascript
复制
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

对于构造函数参数,您将松散参数名称、可选参数和多个签名。

编辑

自从原来的问题被回答后,打字稿改进了这个问题的可能解决方案。随着rest参数和扩展表达式中的元组的增加,我们现在不需要ReplaceReturnType的所有重载

代码语言:javascript
复制
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 new (... args: infer U ) => any ? U: never;
type ReplaceInstanceType<T, TNewInstance> = T extends new (...args: any[])=> any ? new (...a: ArgumentTypes<T>) => TNewInstance : never;

这不仅缩短了,而且解决了许多问题。

  • 可选参数仍然是可选的
  • 参数名被保留。
  • 适用于任意数量的参数
票数 10
EN

Stack Overflow用户

发布于 2021-10-27 18:30:33

我在这里的游戏有点晚,但有一个替代和更短的方法来做它,如果你主要有兴趣使intellisense工作。

可以扩展基类,然后将要省略的成员重新声明为私有成员。这将生成一个类型记录错误,但是添加//@ts-忽略会清除它,不应该影响编译。

当事情很简单的时候,这是我最喜欢的方法。这里没有真正的开销,也没有挑战性的类型语法。这里唯一的缺点是在扩展类上面添加//@ts-忽略可能会阻止您接收与错误扩展基类相关的其他错误消息。

与接受的"pickConstructor“方法相比,该方法的一个优点是该方法不生成任何额外的代码。而"pickConstructor“实际上是在编译后作为一个函数存在,该函数在类定义期间运行。

代码语言:javascript
复制
class Base
{
    public name:string;   
}

// @ts-ignore
class Ext extends Base
{
    private readonly name:undefined; // re-declare
}

let thing:Ext = new Ext();
// The line below...
// Doesn't show up in intellisense
// complains about privacy
// can't be set to anything
// can't be used as an object
thing.name = "test";   // ERROR
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/49429913

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档