我有了可以为空属性的接口。我要检查这是它不为空,然后将对象传递到类型安全的对象
看来分配财产时,一个变量,但是当尝试使用对象作为一个整体,它不能工作了,它不能为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}) {}
解
更换这个简单的检查:
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
。
打字稿目前不会做这种加宽基于控制流分析(据我所知)。这可能是一个很好的功能补充。
现在,虽然有点涉及,您可以使用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更好一点,你可以使用从ExcludePropType
的type-plus
:
function hasMidddle(person: Person): person is ExcludePropType<Person, null> {
return !!person.midddle
}
快速和肮脏的解决办法是只说我知道这是正确的类型,只是将它转换为目标接口。
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}) { }