简体   繁体   English

如何在 Typescript 中返回 NonNullable 类型?

[英]How can I return a NonNullable type in Typescript?

I have code similar to the following:我有类似于以下的代码:

interface Stuff {
  foo: number | null;
  bar: string | null;
}

let stuff: Stuff;

function getStuff(): Stuff;
function getStuff<K extends keyof Stuff>(key: K): NonNullable<Stuff[K]>;
function getStuff<K extends keyof Stuff>(key?: K): Stuff | NonNullable<Stuff[K]> {
  if (key == null)
    return stuff;

  const value = stuff[key];
  if (value == null)
    throw new Error(`${key} is null`);

  return value;
}


const myStuff = getStuff('foo');

Clearly, when you get to the last line of getStuff , value cannot be null or undefined there, but Typescript gives this error:显然,当你到达getStuff的最后一行时, getStuff value不能为nullundefined ,但 Typescript 给出了这个错误:

Type 'Stuff[K]' is not assignable to type 'Stuff | NonNullable<Stuff[K]>'.
  Type 'string | number | null' is not assignable to type 'Stuff | NonNullable<Stuff[K]>'.
    Type 'null' is not assignable to type 'Stuff | NonNullable<Stuff[K]>'.
      Type 'Stuff[K]' is not assignable to type 'Stuff'.
        Type 'string | number | null' is not assignable to type 'Stuff'.
          Type 'null' is not assignable to type 'Stuff'.(2322)

If I remove NonNullable , then it works correctly, but of course myStuff will then require a null check instead, which is what I'm trying to avoid here.如果我删除NonNullable ,那么它可以正常工作,但当然myStuff将需要一个空检查,这是我在这里试图避免的。 Ie I know value cannot be null here, but how do I properly let Typescript know that, without "cheating", eg via return value!即我知道这里的value不能为null ,但是我如何正确地让 Typescript 知道,没有“作弊”,例如通过return value! ? ?


Typescript Playground 打字稿游乐场


Solution based on accepted answer基于已接受答案的解决方案

Ended up adding the following util to our project, with the assertions and a helper type (so we can write Null instead of null | undefined a bunch of places in our code)最终将以下 util 添加到我们的项目中,带有断言和辅助类型(因此我们可以在代码中编写Null而不是null | undefined一堆地方)

// util/null
type Null = null | undefined;

export default Null;

export function isNotNull<T>(value: T)
: value is NonNullable<T> {
  return value != null;
}

export function assertNotNull<T>(value: T, throwError: (value: T) => never)
: asserts value is NonNullable<T> {
  if (value == null) throwError(value);
}

You can just simply do type assertion - return value as NonNullable<Stuff[K]> , or introduce the custom type guard.您可以简单地进行类型断言 - return value as NonNullable<Stuff[K]> ,或者引入自定义类型保护。

The issue you are facing is that TS is not narrowing your control flow null check to NonNullable , but by custom type guard you can force it.您面临的问题是 TS 没有将您的控制流空检查范围缩小到NonNullable ,但是通过自定义类型保护您可以强制执行它。 Consider:考虑:

// type guard narrows to NonNullable
function isNonNullable<T>(a: T): a is NonNullable<T> {
  return a !== null
}
function getStuff(): Stuff;
function getStuff<K extends keyof Stuff>(key: K): NonNullable<Stuff[K]>;
function getStuff<K extends keyof Stuff>(key?: K): Stuff | NonNullable<Stuff[K]> {
  if (key == null)
    return stuff;

  const value = stuff[key];
  if (isNonNullable(value)) {
    return value;
  }
  throw new Error(`${key} is null`);
}

Pay attention that isNonNullable is generic type-guard which you can use with any other value.请注意isNonNullable是通用类型保护,您可以将其与任何其他值一起使用。


Reversed condition will also work correctly:反向条件也将正常工作:

if (!isNonNullable(value)) {
  throw new Error(`${key} is null`);
}
return value;

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

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