Класс и функция возврата обрабатываются по-разному - PullRequest
2 голосов
/ 02 августа 2020

В приведенном ниже коде реализация класса «Validator» выдает ошибку, а функция, возвращающая «Validator» - нет. Я пробовал много изменений, но класс по-прежнему выдает ошибку. Я что-то упустил?

interface Value<Value = unknown> {
    value: Value;
}

interface Validator<Base = unknown> {
    validate<Argument extends Base>(value: Argument): ReturnConstruct<Base, Argument>;
}

type ReturnConstruct<
    Base = unknown,
    Argument extends Base = Base,
    Extent extends Value<Base>  = Value<Base>
> = Extent;

type InstanceConstruct<Base> =  Value<Base> ;

type InferArgument<Type> = Type extends Validator<infer As> ? As : never;

type RecordBase<Schema extends globalThis.Record<PropertyKey, Validator>> = {
    [Key in keyof Schema] : InferArgument<Schema[Key]>
};

// function return the same type with Class
function Fn<
    Container extends Record<PropertyKey, Validator> = Record<PropertyKey, Validator>,
>(
    validators : Container
) : Validator<RecordBase<Container>> {

    return <Validator<RecordBase<Container>>> <any> null;
}

// Class implement same type with function
class Class<
    Container extends Record<PropertyKey, Validator> = Record<PropertyKey, Validator>,
> implements Validator<
    RecordBase<Container>
> {
    constructor(
        public validators : Container,
    ) {
    }

    validate<Argument extends RecordBase<Container>>(
        argument: Argument
    ) : ReturnConstruct<RecordBase<Container>, Argument, InstanceConstruct<RecordBase<Container>>> {

        return <ReturnConstruct<RecordBase<Container>, Argument, InstanceConstruct<RecordBase<Container>>>><any>null;
    }
}

class Type implements Validator<
    any
    > {
    validate<Argument extends any>(value: Argument): ReturnConstruct<any, Argument, InstanceConstruct<any>> {

        return <ReturnConstruct<any, Argument, InstanceConstruct<any>>><any>null;
    }
}

{
    let argument = {
        data1 : new Type(),
        data2 : new Type(),
    };

    new Class(argument)
}


{
    let argument = {
        data1 : new Type(),
        data2 : new Type(),
        // error when using class
        data3 : new Class({
            data1 : new Type(),
            data2 : new Type()
        })
    };

    // error when using class
    new Class(argument)
}

{
    let argument = {
        data1 : new Type(),
        data2 : new Type(),
        // fine when using function
        data3 : Fn({
            data1 : new Type(),
            data2 : new Type()
        })
    };
    // fine when using function
    new Class(argument)
}

странная упаковка в функции производит ошибок нет

function FnWrap<
    Container extends Record<PropertyKey, Validator> = Record<PropertyKey, Validator>,
    >(
    validators : Container
) : Validator<RecordBase<Container>> {

    return new Class(validators);
}
{
    let argument = {
        data1 : new Type(),
        data2 : new Type(),
        // fine when using function
        data3 : FnWrap({
            data1 : new Type(),
            data2 : new Type()
        })
    };
    // fine when using function
    new Class(argument)
}

Я использую машинописный текст 3.9.7, я также пробовал 4.0.0-beta

машинописная ссылка на игровую площадку

1 Ответ

0 голосов
/ 02 августа 2020

Компилятор запутался в болоте типов, с которыми его просят иметь дело.

Я думаю, все, что вам нужно сделать, это помочь ему. Явное приведение класса, который вы добавляете как data3 к правильному типу, позволяет создать класс верхнего уровня без ошибок:

{
    let argument = {
        data1: new Type(),
        data2: new Type(),
        data3: (new Class({
            data1: new Type(),
            data2: new Type()
        })) as Validator<RecordBase<Record<PropertyKey, Validator>>>
    };

    // Instantiates without error now we have the cast above
    new Class(argument)
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...