缩小型接口上的属性(删除空子选项)

问题描述 投票:0回答:3

我有了可以为空属性的接口。我要检查这是它不为空,然后将对象传递到类型安全的对象

看来分配财产时,一个变量,但是当尝试使用对象作为一个整体,它不能工作了,它不能为null缩小的作品。

我不想为失败的设计时类型检查点使用的铸造。

interface Person
{
  midddle:string | null
}

interface MiddleNamePerson
{
  midddle:string
}

function DoWork(person:Person) {
  if(person.midddle)
  {
    const middleName:string = person.midddle; // works
    const middle : MiddleNamePerson = person // Error: Type of 'Person' not Assignable to 'MiddleNamePerson' 
    DoStuff(person) // Error: the argument of 'Person' is not Assignable to parameter
  }

}

function DoStuff(value:{midddle:string}) {}
typescript
3个回答
2
投票

更换这个简单的检查:

if(person.midddle)

一个更好的后卫类型:

if(hasDefined(person, ['midddle']) {

这种型保护可以被定义为:

const hasDefined = <T, K extends keyof T>(argument: T | Defined<T, K>, keys: K[]): argument is Defined<T, K> =>
  keys.every(key => argument[key] != null)

type Defined<T, K extends keyof T = keyof T> = {
  [P in K]-?: Exclude<T[P], undefined | null>
}

说明

控制流不会在工作打字稿上游。通过检查if(person.midddle)我们所知道的中间名是truthy,但Person定义不受影响。这仍然是一个对象,其中的属性称为middle可以null

通过改变它不验证单场的方式,而是整个对象的类型控卫,我们要确保person是整个代码块中一个明确的Person


1
投票

打字稿目前不会做这种加宽基于控制流分析(据我所知)。这可能是一个很好的功能补充。

现在,虽然有点涉及,您可以使用typeguard。

function hasMidddle(person: Person): person is { midddle: string } {
  return !!person.midddle // btw your check will pass with empty string too.
}

function DoWork(person: Person) {
  if (hasMidddle(person)) {
    const middleName: string = person.midddle;
    const middle: MiddleNamePerson = person
    DoStuff(person)
  }
}

如果你想使typeguard更好一点,你可以使用从ExcludePropTypetype-plus

function hasMidddle(person: Person): person is ExcludePropType<Person, null> {
  return !!person.midddle
}

0
投票

快速和肮脏的解决办法是只说我知道这是正确的类型,只是将它转换为目标接口。

const middle : MiddleNamePerson = person as MiddleNamePerson;

推荐的解决方案是使用Type Guard。那么该类型会被自动识别为使用后的缩小型。下面是一个使用型后卫的代码:

export interface Person {
  midddle: string | null;
}

export interface MiddleNamePerson {
  midddle: string;
}

// type guard function
function isMiddleNamePerson(person: Person): person is MiddleNamePerson {
  return person != null && person.midddle != null;
}

export function DoWork(person: Person) {
  if (isMiddleNamePerson(person)) {
    DoStuff(person); // person is automaticaly recognized as MiddleNamePerson becuse of the type guard
  }

}

function DoStuff(value: {midddle: string}) { }
© www.soinside.com 2019 - 2024. All rights reserved.