简体   繁体   English

如何在没有变量的情况下缩小 function 参数的类型

[英]How can I narrow down the type of a function argument without a variable

I have a function that accepts any as parameter:我有一个接受any参数的 function:

declare function postMessage(message: any): void;

I'm trying to call it with an object of certain type as follows:我正在尝试使用某种类型的 object 来调用它,如下所示:

interface NumMsg {type: 'num'; num: number}
interface StrMsg {type: 'str'; str: string}

type Msg = NumMsg | StrMsg;

postMessage({type: 'num', num: 42} as Msg);
postMessage({type: 'str', str: 'Hello World!'} as Msg);

It kind of works but it makes some of the required properties optional - it builds successfully without any errors:它有点工作,但它使一些必需的属性成为可选的 - 它成功构建而没有任何错误:

// Works fine / fails to build:
postMessage({type: 'num', 'str': 'Hello world!'} as Msg);
postMessage({type: 'str', 'num': 42} as Msg);

// Doesn't work fine / build without errors:
postMessage({});
postMessage({type: 'str'} as Msg);
postMessage({type: 'num'} as Msg);

I can solve that issue by defining it as a variable first:我可以通过首先将其定义为变量来解决该问题:

let msg1: Msg = {};
let msg2: Msg = {type: 'str'};
let msg3: Msg = {type: 'num'};

Can I make this work without defining any variables?我可以在不定义任何变量的情况下完成这项工作吗?

I'm assuming you can't change the type of postMessage (for instance, that it's the postMessage defined in the web platform or similar).我假设您不能更改postMessage的类型(例如,它是在 web 平台或类似平台中定义的postMessage )。

I'd solve this by having a wrapper function, not a variable, and not using postMessage directly at all:我会通过使用包装器 function 来解决这个问题,而不是变量,并且根本不直接使用postMessage

function postMsg(message: NumMsg | StrMsg) {
    postMessage(message);
}

(But with a better function name. :-) ) (但有一个更好的 function 名称。:-))

Then these work:然后这些工作:

postMsg({type: "num", num: 42});
postMsg({type: "str", str: "Hellow world!"});

...and these cause errors as desired: ...并且这些会根据需要导致错误:

postMsg({});
postMsg({type: "str"});
postMsg({type: "num"});
postMsg({type: "num", "str": "Hello world!"});
postMsg({type: "str", "num": 42});

Playground link 游乐场链接


If you can change the types of postMessage , just do it directly:如果您可以更改postMessage的类型,则直接进行:

declare function postMessage(message: NumMsg | StrMsg): void;

In the end, I decided to add an overload to the said function: ()最后,我决定为上述function添加一个过载:()

declare function postMessage<T>(message: T): void;

Credits to @jonrsharpe .感谢@jonrsharpe

Now I have the following:现在我有以下内容:

declare function postMessage(message: any): void;
declare function postMessage<T>(message: T): void;

It works even though the former signature is/seems more general.即使前一个签名/似乎更通用,它也可以工作。

Now I can do the following without any issues:现在我可以毫无问题地执行以下操作:

postMessage<Msg>({type: 'num', 'str': 'Hello world!'});
postMessage<Msg>({type: 'str', 'num': 42});

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM