我在typescript playground中尝试了以下代码,并打开了所有选项。我希望TS编译器只允许第一个call()
有效。然而这四个都是。
通过将鼠标悬停在通话上,我看到它们输入为call<"String"|undefined>
。这里发生了什么?有没有办法强制进行这项检查?
interface IEndpoint<RequestType> { }
export const GetConsumer: IEndpoint<undefined> = {};
function call<RequestType>(rpc: IEndpoint<RequestType>, request: RequestType) {}
call(GetConsumer, undefined);
call(GetConsumer, null); // should not be allowed
call(GetConsumer, 1); // should not be allowed
call(GetConsumer, "String"); // should not be allowed
从打字稿specification
未定义的类型是所有类型的子类型。这意味着undefined被认为是所有基本类型,对象类型,联合类型,交集类型和类型参数的有效值。
让我们考虑一下打字稿如何解决以下场景:
class Base{ b: number}
class Derived extends Base{ c: number}
let GetDerived: IEndpoint<Derived>;
call(GetConsumer, new Base());
RequestType
中的泛型参数call
有两种可能的类型:Derived
(基于第一个参数)和Base
(基于第二个参数)。打字稿将选择两者的共同基本类型,因此RequestType
将是Base
。
现在让我们考虑一个例子:
call(GetConsumer, 1);
与第一个例子类似,RequestType
中的call
可以是:undefined
(基于第一个参数)和number
(例如基于第二个参数)。由于undefined
在所有类型的子类型中,它也是数字的子类型,因此最好的共同基类型是number
。
如果您正在寻找不允许最后两次调用的类型,void
可以这样做,因为:
Void类型唯一可能的值为null和undefined。 Void类型是Any类型的子类型和Null和Undefined类型的超类型,但是否则Void与所有其他类型无关。
export const GetConsumer: IEndpoint<void> = {
};
call(GetConsumer, undefined);//still ok
call(GetConsumer, null); // still ok
call(GetConsumer, 1); // error
call(GetConsumer, "String"); // error