typescript 'Pick' 仅指一种类型,但在尝试扩展 Pick< 时在此处用作值
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/49429913/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
'Pick' only refers to a type, but is being used as a value here when trying to extend Pick<
提问by Anarion
I'm trying to have only some properties of ancestorexposed on my descendant. I try to achieve it through Pick
我试图让我的后代只暴露祖先的一些属性。我试图通过Pick
export class Base {
public a;
public b;
public c;
}
export class PartialDescendant extends Pick<Base, 'a' |'b'> {
public y;
}
but I receive two errors -
但我收到两个错误 -
Error: TS2693: 'Pick' only refers to a type, but is being used as a value here.
错误:TS2693:“Pick”仅指一种类型,但在此处用作值。
and
和
Error:TS4020: 'extends' clause of exported class 'PartialDescendant' has or is using private name 'Pick'.
错误:TS4020:导出类“PartialDescendant”的“extends”子句具有或正在使用私有名称“Pick”。
Am I doing something wrong, and is there another way to expose only chosen properties of the base class?
我做错了什么,还有另一种方法可以只公开基类的选定属性吗?
回答by Titian Cernicova-Dragomir
See below for 3.0 solution
3.0解决方案见下文
Pick
is only a type it is not a class, a class is both a type and an object constructor. Types only exist at compile time, this is why you get the error.
Pick
只是一个类型它不是一个类,一个类既是一个类型又是一个对象构造函数。类型仅在编译时存在,这就是您收到错误的原因。
You can create a function which takes in a constructor, and returns a new constructor that will instantiate an object with less fields (or at least declare it does):
您可以创建一个接受构造函数的函数,并返回一个新的构造函数,该构造函数将实例化具有较少字段的对象(或至少声明它):
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
For constructors parameters you will loose things like parameter names, optional parameters and multiple signatures.
对于构造函数参数,您将丢失诸如参数名称、可选参数和多重签名之类的东西。
Edit
编辑
Since the original question was answered typescript has improved the possible solution to this problem. With the addition of Tuples in rest parameters and spread expressionswe now don't need to have all the overloads for ReplaceReturnType
:
由于原始问题得到了回答,打字稿改进了这个问题的可能解决方案。通过在 rest 参数和扩展表达式中添加元组,我们现在不需要所有的重载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;
Not only is this shorter but it solves a number of problems
这不仅更短,而且解决了许多问题
- Optional parameters remain optional
- Argument names are preserved
- Works for any number of arguments
- 可选参数保持可选
- 保留参数名称
- 适用于任意数量的参数