我想在抽象类上创建一个方法来构建它的子类的实例,但前提是定义了props,否则返回undefined.

我试过这个:

abstract class ValueObject<T> {
    protected props: T;

    protected constructor(props: T) {
        this.props = props;
    }

    public static buildIfDefined<C extends ValueObject<CProps>, CProps>(props?: CProps): C | undefined {
        return props !== undefined ?
            new C.constructor(props) :
            undefined;
    }
}

interface ExampleProps {
    value: number,
}

class Example extends ValueObject<ExampleProps> {
    constructor(value: number) {
        super({value});
    }
}

function buildExampleIfValueDefined(value: number|undefined): Example|undefined {
    return Example.buildIfDefined(value);
}

但是对于第C.constructor(props)行,我收到以下错误:

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

我做错了什么?

我可以用一种更好的方法来实现这一点吗?

推荐答案

示例代码有两个问题:

  1. 你问的关于try 使用C.constructor的问题

  2. 示例用法是try 将ValueObject<number>视为Example,但ExampleValueObject<{value: number;}>.

请回复您的后续 comments :

从技术上讲,我想避免在每次调用构造函数之前判断是否定义了什么,我不想在每个子类中为它定义特定的函数,所以我希望在抽象上继承它,或者可能在ValueObjectFactory个类中.但在这两种情况下,我不知道如何准确地定义类型……

当我问独立函数是否适合时,您说它适合,所以:您可以这样定义该函数:

function buildIfDefined<CProps>(
    c: new (...args: any[]) => ValueObject<CProps>,
    props?: CProps
): ValueObject<CProps> | undefined {
    if (props === undefined) {
        return undefined;
    }
    return new c(props);
}

它接受要使用的构造函数和要使用的props ,或undefined.如果props 为undefined,则返回undefined,否则使用props 构造对象并返回.

用途:

function buildExampleIfValueDefined(
    props?: { value: number }
): Example | undefined {
    return buildIfDefined(Example, props);
}

Playground link

请注意,它不允许您直接将ValueObject作为构造函数传递,也不允许将任何其他abstract类作为构造函数传递,因为构造函数参数的类型签名需要公共构造函数.


回答你原来的问题:

Re#1,C只是一个类型,而不是错误提到的值.您可以通过根本不try 使用C来修复该错误,使用this而不是C.constructor.在static方法中,this是该方法被调用的构造函数(这只是this的正常行为,它被设置为您对其调用该方法的对象,除非有什么适当的措施来防止这种情况).所以,如果你在通话过程中拨打Example.buildIfDefined,thisExample.

TypeScrip不会喜欢你的ValueObject类,因为它看起来,就像你试图实例化一个abstract类.我们可以通过添加我们自己的支票来解决这个问题,然后告诉Tyescript不要担心:

public static buildIfDefined<CProps>(
    props?: CProps
): ValueObject<CProps> | undefined {
    if (this === ValueObject) {
        throw new Error(
            "ValueObject.buildIfDefined cannot be called directly, only via a subclass"
        );
    }
    if (props === undefined) {
        return undefined;
    }
    const ctor = this as unknown as (new (props: CProps) => ValueObject<CProps>); 
    return new ctor(props);
}

用途:

function buildExampleIfValueDefined(
    props?: { value: number; }
): Example | undefined {
    return Example.buildIfDefined(props);
    //                            ^^^^^
}

Playground link

这不具有独立函数必须防止abstract个构造函数的自动处理,所以我们必须使用类型断言来解决这个问题.

Typescript相关问答推荐

Angular 17 -如何在for循环内创建一些加载?

了解TS类型参数列表中的分配

用泛型类型覆盖父类函数导致类型y中的Property x不能赋给基类型Parent中的相同属性."'''''' "

有没有可能使用redux工具包的中间件同时监听状态的变化和操作

TypeScript:在作为参数传递给另一个函数的记录中对函数的参数实现类型约束

如何以Angular 形式显示验证错误消息

在实现自定义主题后,Angular 不会更新视图

具有自引用属性的接口

如何将别名添加到vitest配置文件?

为什么我在这个重载函数中需要`as any`?

从类型脚本中元组的尾部获取第n个类型

Typescript,如何在通过属性存在过滤后重新分配类型?

三重融合视角与正交阵

递归类型别名的Typescript 使用

在ts中获取级联子K类型?

Typescript 确保通用对象不包含属性

使用受保护的路由和入门来响应路由

在 next.js 13.4 中为react-email-editor使用forwardRef和next/dynamic的正确方法

在Typescript 中,是否有一种方法来定义一个类型,其中该类型是字符串子集的所有可能组合?

如何使用 TypeScript 接口中第一个属性的值定义第二个属性