类构造器类型

时间:2018-12-09 16:44:32

标签: typescript

我想在我的课程中要求一种或另一种构造函数:

const instance: MyClass = new MyClass({ digit: 5 });

...或...

const instance: MyClass = new MyClass({ letter: 'x' });

它不能同时是两个,也不能是其他一些对象。

此刻我有这个:

interface MyClassConstructor {
    digit?;
    letter?;
}
interface MyClassDigit extends MyClassConstructor {
    digit: number;
}
interface MyClassLetter extends MyClassConstructor {
    letter: string;
}

class MyClass {
    constructor(obj: MyClassDigit | MyClassLetter) {
        if (obj.digit) {
            // ...
        } else if (obj.letter) {
            // ...
        }
    }
}

但是我不认为这样做是正确的方式...

2 个答案:

答案 0 :(得分:1)

对于您的解决方案,我不会做太多改变。我不会同时具有两个属性的基本接口。我只需要使用一个联合和一个in类型防护:

interface MyClassDigit {
    digit: number;
}
interface MyClassLetter {
    letter: string;
}

class MyClass {
    constructor(obj: MyClassDigit | MyClassLetter) {
        if ('digit' in obj) {
            // obj is MyClassDigit
        } else {
            // obj is MyClassLetter
        }
    }
}

如果您有更多参数并且只需要一个成员,则可以使用条件类型自动生成类型:

interface MyParams {
    digit?: number;
    letter?: string;
}
type RequireOne<T> = (keyof T) extends infer K ?
    K extends keyof T ?
    Required<Pick<T, K>> : never : never

class MyClass {
    constructor(obj: RequireOne<MyParams>) {
        if ('digit' in obj) {
            // obj has digit
        } else {
            // obj has letter 
        }
    }
}

答案 1 :(得分:1)

重载constructor

interface WithDigit {
    digit: number
}

interface WithLetter {
    letter: string
}

class MyClass {
    constructor(options: WithDigit);
    constructor(options: WithLetter);
    constructor(options: WithLetter | WithDigit) {
        if ('digit' in options) {
            /* */
        }

        if ('letter' in options) {
            /* */
        }
    }
}

这将确保只接受一个。

new MyClass({ digit: 0 });              // OK
new MyClass({ letter: 'a' });           // OK
new MyClass({ digit: 0, letter: 'a' }); // Error