TS4.4 更新:
TypeScript 很快将允许使用control flow analysis of aliased conditions,这意味着将isShareable 之类的条件保存为const 可能允许稍后将其用作类型保护。不幸的是,这里的代码似乎有点恶化,因为share 是Navigator 的一个已知属性,你不能再只是merge 它了。
像isShareable 这样的别名条件只有在你测试的属性是readonly 时才有效,因为编译器都知道,有人可能会在你设置isShareable 之后但在你调用之前设置window.navigator.share = undefined window.navigator.share。如果您无法控制事物是否为readonly,这将是一个相当大的障碍。不过,如果它看起来像这样:
interface Navigator extends Omit<typeof window.navigator, "share"> {
readonly share?: (data?: ShareData) => Promise<void>;
}
declare const _window: Omit<typeof window, 'navigator'> &
{ readonly navigator?: Navigator }
那么在 TypeScript 4.4 中,这不会是错误:
const isShareable =
(_window.navigator && _window.navigator.share);
const handleShareStored = async () => {
if (isShareable) {
try {
await _window.navigator.share({ // no error in TS4.4+
text: "Checkout Verishop!",
title: "Share Verishop",
url: "referralUrl"
});
} catch (e) {
_window.alert(e);
}
}
};
Playground link to code
TS4.4 之前的答案:
TypeScript 目前不允许您将类型保护结果保存在一个变量中,以便以后使用,就像您尝试使用 isShareable 所做的那样。在 TypeScript 的 GitHub 问题中有两个公开的建议:microsoft/TypeScript#12184 和 microsoft/TypeScript#24865。这些问题似乎都没有太大的吸引力,但我想你可以去这些问题并给他们一个 ? 或描述你的用例(如果它令人信服)。问题很可能是实现并保持编译器性能并非易事。
你现在能做什么?显而易见且不令人满意的答案是不要尝试提前进行类型保护,而是在您想要使用受保护的 window.navigator.share 函数之前进行:
// just do the check inline
const handleShareExplicit = async () => {
if (window.navigator && window.navigator.share) {
try {
await window.navigator.share({ // no error
text: "Checkout Verishop!",
title: "Share Verishop",
url: "referralUrl"
});
} catch (e) {
window.alert(e);
}
}
};
这并不是真的那么糟糕,因为它仍然相当简洁......(window.navigator && window.navigator.share) 仍然适合一行。但是有些人可能会遇到类似的问题,即类型保护是一项更复杂的检查,或者您可能从哲学上反对多次进行检查。在这种情况下,您可以尝试不同的方法:
// store a reference to the function if it exists
const share =
window.navigator && window.navigator.share
? window.navigator.share // .bind(window.navigator) ?? see note below
: undefined;
const handleShare = async () => {
if (share) {
try {
await share({ // no error
text: "Checkout Verishop!",
title: "Share Verishop",
url: "referralUrl"
});
} catch (e) {
window.alert(e);
}
}
};
不存储类似boolean 的变量isShareable,而是存储类型为((data?: ShareData) => Promise<void>) | undefined 的等效变量share。然后检查 if (share) { share(...) } 与您所做的具有相同的语义,除了在这种情况下编译器可以很容易地看到您正在使用您刚刚检查的东西。
(请注意,根据window.navigator.share() 的实现方式,它可能需要this 上下文为window.navigator。如果是这样,那么您可能希望将share 保存为window.navigator.share.bind(window.navigator) 而不仅仅是@987654354 @. 无论如何,这样做可能没有什么坏处。这取决于你。)
好的,希望对您有所帮助。祝你好运!
Link to code