根据对象类型进行切换

时间:2019-06-13 22:01:37

标签: typescript

如果我具有联合类型,则如何构造控制流以对该值进行操作,使其作为它包含的实际具体类型?有时我可以在运行时进行instanceof测试,然后将其强制转换,但这似乎既笨拙,不安全,也不总是可能的(您不能实例化类型数组)。当实际类型为并集时,如何安全地对值进行运算?

在下面的示例中,food.value导致类型错误。有没有什么方法可以使编译器无需显式强制转换就可以理解这是{value:string}类型?

type FoodSet = (string | { value: string })[]

const myValues : FoodSet = [
    "hamburger",
    "cheeseburger",
    {value: "salad"},
    "fish",
    {value: "quinoa"}
]

myValues.forEach(food => {
    if (food instanceof String) {
        console.log(food)
    } else {
        console.log(food.value) // <-- error here
    }
})

我会喜欢

switch(typeof food) {
    case string:
        console.log(food)
    case {value:string}:
        console.log(food.value)
}

3 个答案:

答案 0 :(得分:3)

您的初次尝试非常接近!问题是food instanceof String不是完全正确:如果FoodSet(String | { value: string })[](请注意大写字母S),这将是可行的。

要检查food是否为string,应改用typeof food === "string"。这样可以将else分支中的类型正确地缩小为{ value: string }

type FoodSet = (string | { value: string })[]

const myValues : FoodSet = [
    "hamburger",
    "cheeseburger",
    {value: "salad"},
    "fish",
    {value: "quinoa"}
]

myValues.forEach(food => {
    if (typeof food === "string") {
        console.log(food)
    } else {
        console.log(food.value)
    }
})

答案 1 :(得分:1)

Javascsript很奇怪,而且TypeScript在设计上甚至没有尝试在运行时进行任何改进。在Javascript中,有两种字符串值-基本值和对象(or boxed strings)。

因此,您必须同时检查两者,或仅在代码中只使用一种字符串。通常的建议是完全避免使用String类。您可以在javascript控制台中看到不同之处:

let primitiveString = 'a';
> 
typeof primitiveString === 'string'
> true  // note that the result of runtime `typeof` is a string
primitiveString instanceof String
> false // primitiveString was not created with the String() constructor, of course
let objectString = new String('a');
>
typeof objectString === 'string'
> false   // typeof objectString returns 'object'
primitiveString instanceof String
> true  
objectString === primitiveString
> false
objectString == primitiveString
> true
  

我会喜欢

switch(typeof food) {
    case string:
        console.log(food)
    case {value:string}:
        console.log(food.value)
}

TypeScript中有两个不同的typeof运算符。

一个仅是编译时,它允许引用某些变量或函数的类型。

另一个是运行时typeof,它是the same as in javascript,它返回的信息量非常有限,因为TypeScript不会在运行时生成任何类型的类型信息。

因此,每次要在运行时检查对象的类型时,都需要编写一系列if语句,并根据情况进行不同类型的检查:

  • typeof,如果您要检查诸如stringnumberbooelanfunction或{{ 1}}(object的意思是“其他”)

  • object,如果您想知道使用哪个构造函数创建对象(请注意,如果该值是作为对象文字创建的,它将是instanceof的实例,但是可能很好地与某些类兼容,因为对象文字也可以具有方法)

  • Object运算符,如果要检查对象has some property or method

  • in检查某物是否为数组

以此类推。

编译器在您的代码中检测到错误

Array.isArray()

因为对于原始字符串myValues.forEach(food => { if (food instanceof String) { console.log(food) } else { console.log(food.value) // <-- error here } }) 将为false,所以将执行instanceof String分支以尝试访问字符串上不存在的false属性。检查字符串类型的常用方法是

value

如另一个答案所述。

答案 2 :(得分:1)

https://www.typescriptlang.org/docs/handbook/advanced-types.html#user-defined-type-guards

我想要的是用户定义的类型警卫


interface Bird {
    fly();
    layEggs();
}

interface Fish {
    swim();
    layEggs();
}


function isFish(pet: Fish | Bird): pet is Fish {
    return (<Fish>pet).swim !== undefined;
}

if (isFish(pet)) {
    pet.swim();
}
else {
    pet.fly();
}