Тип Typescript oneOf для классов

#typescript #inheritance #multiple-inheritance #typescript-typings

#typescript #наследование #множественное наследование #typescript-типизации

Вопрос:

 class CoreClass {
    coreProp: string
    // cannot do classABProp: string | number
    // as it interferes with persistence and cannot be easily 
    // used to define database schema. 
}

class ClassA extends CoreClass {
    classAProp: string

};

class ClassB extends CoreClass {
    classBPorp: number
};

class SubClass extends CoreClass {
    // Expected Props    
    // coreProp: string
    // classAProp: string || classBPorp: number
    // should have atleast one of the two.

}
  

Итак, я искал аккуратный способ сделать это.
Я не отказываюсь определять подкласс дважды, что, по сути, делает одно и то же.

У меня есть конструктор для каждого класса, поэтому я действительно не собираюсь определять отдельные типы для достижения того же самого.

Кажется тривиальной проблемой, но я не могу разобраться в ней.

Любая помощь по тому же вопросу была бы высоко оценена.

Комментарии:

1. Мне не ясно, что Subclass должно быть… Если вам нужен тип, представляющий какой-либо подкласс, вы могли бы использовать тип объединения type Subclass = ClassA | ClassB

2. Ну, у подкласса будет свой собственный конструктор, поэтому присвоение ему типа — не лучший способ сделать это.

3. Итак, Subclass нужно наследовать от обоих ClassA и ClassB ? Или вы просто хотите убедиться, что он реализует тот же интерфейс, что и ClassA и Class B

4. SubClass должен обладать всеми свойствами CoreClass и должен иметь classAProp или classBProp , но должен иметь хотя бы один из двух реквизитов. Это то, что я имел в виду под oneOf type, поскольку типы on могли бы легко сделать это с помощью оператора объединения, но не очень, как сделать то же самое с классами.

Ответ №1:

Похоже, вы хотите определить интерфейсы вместо классов здесь. Как насчет:

 interface CommonInterface {
  coreProp: string
}

interface InterfaceA extends CommonInterface {
    classAProp: string
};

interface InterfaceB extends CommonInterface {
    classBProp: number
};

type CoreInterface = InterfaceA | InterfaceB;

const testStringProp: CoreInterface = { coreProp: 'test', classAProp: "testString" };
const testNumberProp: CoreInterface = { coreProp: 'test', classBProp: 43 };

const testError: CoreInterface = { coreProp: 'test' }; 
//error: needs either classAProp or classBProp
  

Реализация интерфейсов путем создания экземпляров новых объектов:

 class CommonClass {
    coreProp: string
    // ...
}

class ClassA extends CommonClass {
    classAProp: string;

    constructor(props: InterfaceA) {
        super();
        this.coreProp = props.coreProp;
        this.classAProp = props.classAProp;
    }
};

class ClassB extends CommonClass {
    classBProp: number;

    constructor(props: InterfaceB) {
        super();
        this.coreProp = props.coreProp;
        this.classBProp = props.classBProp;
    }
};

class ClassAorB extends CommonClass {
    classAProp: string;
    classBProp: number;

    constructor(props: CoreInterface) {
        super();
        this.coreProp = props.coreProp;
        const propsA = props as InterfaceA;
        const propsB = props as InterfaceB;
        if (propsA.classAProp) {
            this.classAProp = propsA.classAProp
        }
        if (propsB.classBProp) {
            this.classBProp = propsB.classBProp
        }
    }
};


const objOfClassA = new ClassA({ coreProp: 'test', classAProp: 'testString' });
const objOfClassB = new ClassB({ coreProp: 'test', classBProp: 43 });
const objA = new ClassAorB({ coreProp: 'test', classAProp: 'testing' });
const objB = new ClassAorB({ coreProp: 'test', classBProp: 43 });

const testError = new ClassB({coreProp: 'test'}); 
//error: needs classBProp
const testAntotherErr = new ClassAorB({coreProp: 'test'}) 
//error: needs either classAProp or classBProp
  

Комментарии:

1. Ну, я упоминал ‘У меня есть конструктор для каждого класса, поэтому я действительно не собираюсь определять отдельные типы для выполнения одного и того же.’. Это фиктивные классы, у реальных классов от 15 до 20 реквизитов, на самом деле невозможно использовать типы в таком сценарии, нужно использовать классы и наследование.

2. Обновлено, чтобы включить пример создания экземпляра класса

3. Итак, проблема с этим подходом заключается в том, что если я выполняю ` objA.classBProp`, это не выдает ошибку. Даже несмотря на то, что objA не имеет classBProp.