繁体   English   中英

推断类的 object 的类型

[英]Infer type of object of classes

构建一个表单配置构建器,想要动态推断类型,这里是最小的复制代码

interface Meta {
    optional: boolean
}

class Base<Type = any> {
    readonly _type!: Type
    baseMeta: Meta

    constructor() {
        this.baseMeta = {
            optional: false,
        }
    }

    optional() {
        this.baseMeta.optional = true
        return this;
    }
}

class FieldText extends Base<string> {

}

class FieldNumber extends Base<number> {

}


class Field {
    static text() {
        return new FieldText();
    }

    static number() {
        return new FieldNumber();
    }
}

const fields = {
    fieldText: Field.text(),
    fieldNumber: Field.number(),
    fieldTextOptional: Field.text().optional(),
    fieldNumberOptional: Field.number().optional(),
}

给定上面的代码,我想实现以下类型之一,不管是哪一个

type ExpectedType = {
    fieldText: string;
    fieldNumber: number;
    fieldTextOptional: number | undefined;
    fieldNumberOptional: number | undefined;
}

也不错

type ExpectedTypeWithOptionalKeys = {
    fieldText: string;
    fieldNumber: number;
    fieldTextOptional?: number;
    fieldNumberOptional?: number;
}

我已经开始推断类型,但无法弄清楚为什么不考虑可选属性

type ExtractFieldType<O, T> = O extends true ? T | undefined : T;

type SchemaType<T extends Record<string, Base>> = {
    [Property in keyof T]: ExtractFieldType<T[Property]['baseMeta']['optional'], T[Property]['_type']>;
};

type Schema = SchemaType<typeof fields>;

type Schema导致:

type Schema = {
    fieldText: string;
    fieldNumber: number;
    fieldTextOptional: string;
    fieldNumberOptional: number;
}

这个O extends true? T | undefined: T O extends true? T | undefined: T O extends true? T | undefined: T总是返回 T,不考虑 optional 的实际值

编辑:

在对@kelly为可选 function 提供值的答案进行了一番摸索之后,这是最终结果:

    optional<T extends boolean>(value?: T): Base<Type, T> {
        const optional = typeof value === 'boolean' ? value : true;
        this.baseMeta.optional = optional as Optional;
        return this as unknown as Base<Type, T>;
    }

首先你不能有一个默认值,然后 Typescript 会生气:

Type 'boolean' is not assignable to type 'T'.
  'boolean' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint 'boolean'.(2322)

因此,我们只需将 value 设为optional ,然后 rest 就像 Kelly 解释的那样工作

除了return this as unknown as Base<Type, T>;

如果您删除as unknown部分,则会收到以下错误:

Conversion of type 'this' to type 'Base<Type, T>' may be a mistake because neither type sufficiently overlaps with the other. If this was intentional, convert the expression to 'unknown' first.
  Type 'Base<Type, Optional>' is not comparable to type 'Base<Type, T>'.
    Type 'Optional' is not comparable to type 'T'.
      'Optional' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint 'boolean'.(2352)

这是Typescript Playground中的最终工作

Meta中的optional类型始终boolean 您需要将值存储在泛型中以供以后使用:

interface Meta<Optional extends boolean> {
    optional: Optional;
}

class Base<Type = any, Optional extends boolean = false> {
    readonly _type!: Type
    baseMeta: Meta<Optional>

    constructor() {
        this.baseMeta = {
            optional: false as Optional,
        }
    }

    optional(): Base<Type, true> {
        this.baseMeta.optional = true as Optional; // needs unsafe assert, or alternatively //@ts-ignore
        return this as Base<Type, true>;
    }
}

然后,当您使用optional更改它时,欺骗 TypeScript 相信您正在返回Base<Type, true>

你只需要改变它。 您的原始解决方案现在有效。


解决评论中的后续问题:

optional<T extends boolean = true>(value: T = true): Base<Type, T> {
    this.baseMeta.optional = value as Optional;
    return this as Base<Type, T>;
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM