开发者问题收集

如何让 TypeScript 知道我的变量不再未定义

2021-12-20
2847

这是我的情况:

我正在使用 Remix 加载器 ,它从 URL 获取参数,但参数定义为 string | undefined

如果变量为 undefined ,我想抛出一个 重定向

export const loader: LoaderFunction = async ({ params }) => {
  const { myVar } = params; // myVar: string | undefined 
  definedOrRedirect(myVar, "/"); // Checks if undefined
  return fetchSomething(myVar); // myVar: string | undefined
};

有没有办法让 typescript 知道如果它没有抛出 myVar 就不是未定义的?

2个回答

您可以将 throwIfUndefined 设为 断言函数 ,以将其参数的类型缩小为域中不包含 undefined 的类型。断言函数具有形式为 asserts x is Y 断言类型谓词 作为其返回类型,其中 x 是该函数参数之一的名称, Ytypeof X 的子类型,我们将 x 缩小为假设函数成功返回。断言函数不能返回已定义的值;它们基本上是 void 返回函数。

对于 throwIfUndefined ,以下是执行它的正常方法,作为函数语句:

function throwIfUndefined<T>(x: T | undefined): asserts x is T {
    if (typeof x === "undefined") throw new Error("OH NOEZ");
}

您也可以将其写为箭头函数,但您需要明确 注释 变量及其类型,以便控制流分析正确进行:

const throwIfUndefined: <T, >(x: T | undefined) => asserts x is T = x => {
    if (typeof x === "undefined") throw new Error("OH NOEZ");
}

两种方式都可以:

const Index = ({ params }: { params: { myVar: string | undefined } }) => {
    const { myVar } = params // myVar: string | undefined
    // myVar.toUpperCase // <-- error, Object is possibly 'undefined'
    throwIfUndefined(myVar);
    return myVar.toUpperCase() // no error now
}

try {
    console.log(Index({
        params: {
            myVar: Math.random() < 0.5 ? "hello" : undefined
        }
    })) // 50% "HELLO" 
} catch (e) {
    console.log(e); // 50% "OH NOEZ"
}

游乐场链接到代码

jcalz
2021-12-20

您可以跳过 definedOrRedirect 并使用显式检查:

export const loader: LoaderFunction = async ({ params }) => {
  const { myVar } = params; // myVar: string | undefined 
  if (myVar == undefined) {
    return redirect("/");
  }
  return fetchSomething(myVar); // myVar: string
}

或者您可以保留 definedOrRedirect 并使用断言声明它,如 jcalz 所建议的:

function definedOrRedirect(variable, path): asserts variable is string
{
  if (variable == undefined) {
    return redirect(path);
  }
}

export const loader: LoaderFunction = async ({ params }) => {
  const { myVar } = params; // myVar: string | undefined 
  definedOrRedirect(myVar, "/");
  return fetchSomething(myVar); // myVar: string
}
md2perpe
2021-12-20