typescript - 'Pick' 仅指一种类型,但在尝试扩展 Pick<

标签 typescript

我试图只让祖先的一些属性暴露在我的后代上。我尝试通过Pick

来实现
export class Base {
    public a;
    public b;
    public c;
}

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

但我收到两个错误 -

Error: TS2693: 'Pick' only refers to a type, but is being used as a value here.

Error:TS4020: 'extends' clause of exported class 'PartialDescendant' has or is using private name '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

对于构造函数参数,您将丢失参数名称、可选参数和多个签名等内容。

编辑

由于回答了原始问题, typescript 改进了该问题的可能解决方案。添加 Tuples in rest parameters and spread expressions我们现在不需要 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 new (... args: infer U ) => any ? U: never;
type ReplaceInstanceType<T, TNewInstance> = T extends new (...args: any[])=> any ? new (...a: ArgumentTypes<T>) => TNewInstance : never;

这不仅更短而且解决了很多问题

  • 可选参数保持可选
  • 保留参数名称
  • 适用于任意数量的参数

关于typescript - 'Pick' 仅指一种类型,但在尝试扩展 Pick<,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49429913/

相关文章:

javascript - 如何在 Angular 6 中加载自定义字体?

javascript - 每个单词的第一个字母大写并处理拉丁字符

typescript - Ramda 的 LensProp 类型定义

javascript - 在 Typescript 中创建/修复 node-json2html 的声明文件

javascript - 无法读取未定义的 angular2 的属性

typescript - Angular2 + typescript + jspm : No provider for Http ( App -> Provider -> Http )

Angular 4 : `ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked

javascript - 如何检查变量是否不是假值但 0 在 Javascript 中传递

angular - 模板引用变量中的 ref- 前缀和 # 有什么区别(Angular 2)

javascript - 如何在js文件中执行ts函数?