打字稿检查未定义并分配给变量

时间:2019-07-05 16:54:36

标签: typescript

我不确定为什么Typescript为以下代码给出类型错误:

ElseBB

打字稿抱怨这行BasicBlocks

它表示type ShareData = { title?: string; text?: string; url?: string; }; // extending window.navigator, which has a type of Navigator interface Navigator { share?: (data?: ShareData) => Promise<void>; } const isShareable = window.navigator && window.navigator.share; const handleShare = async () => { if (isShareable) { try { await window.navigator.share({ text: 'Checkout Verishop!', title: 'Share Verishop', url: 'referralUrl', }); } catch (e) { window.alert(e); } } }; 可能未定义。但是,我使用await window.navigator.share({来确保share未被定义。

我也尝试定义isShareable,如下所示:window.navigator.share,但会遇到相同的错误。

理想情况下,我可以创建一个函数来检查是否定义了isShareable并进行类型检查。

可以将以上所有代码粘贴到https://www.typescriptlang.org/play

谢谢!

3 个答案:

答案 0 :(得分:1)

TypeScript当前不允许您将类型保护结果保存在变量中,以供以后尝试使用isShareable的方式使用。在TypeScript的GitHub问题中,有两个公开的建议要求这样做:microsoft/TypeScript#12184microsoft/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而不是存储类似share的变量((data?: ShareData) => Promise<void>) | undefined。然后,检查if (share) { share(...) }具有与您所做的相同的语义,只是在这种情况下,编译器可以轻松地看到您正在使用刚刚检查的内容。

(请注意,根据实现window.navigator.share()的方式,可能需要将this上下文设为window.navigator。如果是这样,则可能需要将share保存为window.navigator.share.bind(window.navigator)而不只是window.navigator.share。在任何情况下,这样做都无妨。这取决于您。)

好的,希望能有所帮助。祝你好运!

Link to code

答案 1 :(得分:0)

您可以使用类型转换来确保导航器具有share方法,并且您需要使share成为必需的道具,因为您拥有它的方式可能是不确定的。围栏中的此代码没有错误。

type ShareData = {
  title?: string;
  text?: string;
  url?: string;
};

// extending window.navigator, which has a type of Navigator
interface Navigator {
  share: (data?: ShareData) => Promise<void>;
}

const nav = window.navigator as Navigator;

  const handleShare = async () => {
      try {
        await nav.share({
          text: 'Checkout Verishop!',
          title: 'Share Verishop',
          url: 'referralUrl',
        });
      } catch (e) {
        window.alert(e);
      }
    }
  };

答案 2 :(得分:0)

您可以使用type guard帮助TypeScript安全地确定变量的接口。例如,

type ShareData = {
  title?: string;
  text?: string;
  url?: string;
};

// extending window.navigator, which has a type of Navigator
interface SharableNavigator extends Navigator {
  share: (data?: ShareData) => Promise<void>;
}

function isSharableNavigator(nav: Navigator): nav is SharableNavigator {
    return typeof (nav as SharableNavigator).share === 'function';
}

const handleShare = async () => {
  if (isSharableNavigator(window.navigator)) {
    try {
      await window.navigator.share({
        text: 'Checkout Verishop!',
        title: 'Share Verishop',
        url: 'referralUrl',
      });
    } catch (e) {
      window.alert(e);
    }
  }
};