在typescript中覆盖方法参数和返回类型

时间:2016-12-09 07:53:32

标签: javascript typescript

我不想在抽象类中描述一个抽象方法,它可以取numberstring并返回数字或字符串; 我正在使用|符号告诉方法它的参数和返回类型可能因字符串而异 然后我创建了两个类bc,这些类从抽象类a扩展并尝试覆盖方法test(),没有参数和返回类型变化。
接下来,我声明变量x哪个类型可能类似于bc类,我正在根据随机语句创建其中一个类的实例。
最后我试着调用test()方法,但TS编译器给出了下面描述的错误。

abstract class a {
    abstract test(x: string | number): string | number;
}

class b extends a {
    test(x: number): number {
        return x;
    }
}


class c extends a {
    test(x: string): string {
        return x;
    }
}

let x: b | c;


if (Math.random() > 0.5) {
    x = new b()
} else {
    x = new c()
};

x.test(1)

这是来自TS编译器的错误:

Cannot invoke an expression whose type lacks a call signature. Type '((x: number) => number) | ((x: string) => string)' has no compatible call signatures. (property) test: ((x: number) => number) | ((x: string) => string)

也许我使用了错误的方法或者我误解了TS文档,如果是这样的话 - 你能不能指出我更好的方式来实现我的目标。
对于糟糕的班级名称和没有任何“小提琴”,我很抱歉 - 我找不到任何突出TS编译器错误的js playground网站,所以我推荐官方TS Playground

2 个答案:

答案 0 :(得分:2)

当你在if块中创建类的实例时,typescript编译器无法确定x将是哪种类型。没关系,但问题是你然后尝试使用数字调用测试函数,这只有在类型为b时才可能。由于编译器认为x可能是c类型,因此会出错。

您需要向编译器保证,当您调用test时,您调用的函数将始终与提供的参数匹配。

你可以:

  1. 更改调用签名以便两者都接受任何类型,这样编译器调用哪个方法无关紧要:

    class b extends a {
        test(x: any) {
            return x;
        }
    }
    
    class c extends a {
        test(x : any) {
            return x;
        }  
    }
    
  2. 在if块中调用方法:

    if (Math.random() > 0.5) {
        x = new b();
        x.test(1);
    } else {
        x = new c();
        x.test('1');
    }
    
  3. 键入方法调用:

    if (x instanceof b)
        x.test(1);
    else if(x instanceof c)
        x.test('1');
    
  4. 查看关于联盟类型和打字机的手册:https://www.typescriptlang.org/docs/handbook/advanced-types.html#union-types

    编辑: 为您提供的建议,以便您无需在每次调用时键入类型,都可以在方法本身中完成类型检查。这样做的缺点是能够使用不正确的参数调用该方法而不会收到编译器的警告。以下是一个示例:

    abstract class a {
        protected abstract internal(x: any): any;
    
        public test(x: string | number): string | number {
            return this.internal(x);
        }
    }
    
    class b extends a {
        protected internal(x) {
            if (typeof x === "number") 
                return x;
            else
                throw new Error("Invalid argument");
        }
    }
    
    
    class c extends a {
        protected internal(x) {
            if (typeof x === "string")
                return x;
            else
                throw new Error("Invalid argument");
        }
    }
    
    let x: b | c;
    
    
    if (Math.random() > 0.5) {
        x = new b();
    } else {
        x = new c();
    }
    
    x.test(1);
    

答案 1 :(得分:1)

您将x声明为b或c然后尝试重新定义它只使b或仅c(我理解但我的理解有限) 根据您提供的编辑器,下面的代码可以工作:

abstract class a {
abstract test(input: number | string )   
}

class b extends a {
    test(x: string) {
        return x;
    }
}

class c extends a {
    test(x : number) {
        return x;
    }  
}

let x//: b | c;

if (Math.random() > 0.5) {
    x = new b()
} else {
    x = new c()
}

x.test(1)