打字稿联盟类型:处理界面

时间:2016-03-01 15:28:23

标签: typescript

处理这种情况的正确方法是什么,你有两个足够相似的接口,你想通过同一个逻辑运行它们:

interface DescriptionItem {
    Description: string;
    Code: string;
}
interface NamedItem {
    Name: string;
    Code: string;
}

function MyLogic(i: DescriptionItem | NamedItem) {
    var desc = (<DescriptionItem>i).Description || (<NamedItem>i).Name;

    return i.Code + ' - ' + desc;
}

这有效;但是,我的问题是改进var desc = ...行。我有什么最好的选择?或者有没有更好的方法来处理Typescript中的这种情况?

3 个答案:

答案 0 :(得分:6)

TypeScript interfaces仅在编译时存在,因此您无法在运行时测试接口类型。您在问题中指定的代码是有意义的,可能是您的最佳选择。

但是,如果您可以灵活地将interfaces更改为classes,则可以使用TypeScript的类型保护来执行更优雅的类型检查:

class DescriptionItem {
    Description: string;
    Code: string;
}
class NamedItem {
    Name: string;
    Code: string;
}

function MyLogic(i: DescriptionItem | NamedItem) {
    let desc: string;
    if (i instanceof DescriptionItem) {
        desc = i.Description;
    } else {
        desc = i.Name;
    }

    return i.Code + ' - ' + desc;
}

答案 1 :(得分:2)

我知道这个问题很老,但是我正在学习相同的问题,所以我一直在玩同样的问题。和&进行类型并集时。

有一些选项可以解决此问题(对棉绒友好)。 最好的方法是在所有界面(narrow interface)中使用区分符。

//First create a super-interface that have the discriminator
interface B
{
    kind:'b1'|'b2' //define discriminator with all the posible values as string-literals (this is where the magic is)
}

interface B1 extends B
{
    kind: 'b1' //now narrow the inherited interfaces literals down to a single 
    //after that add your interface specific fields
    data1: string;
    data: string;
}

interface B2 extends B
{
    kind:'b2' //now narrow the inherited interfaces literals down to a single
    //after that add your interface specific fields
    data2: string;
    data: string;
}

//lets initialize 1 B1 type by using the literal value of a B1 interface 'b1'
var b1: B1|B2 = {
    kind:'b1',
    data: 'Hello From Data',
    data1:'Hello From Data1'
    //typescript will not allow you to set data2 as this present a B1 interface
}
//and a B2 Type with the kind 'b2'
var b2: B1|B2 = {
    kind: 'b2',
    data: 'Hello From Data',
    //typescript will not allow you to set data1 as this present a B2 interface
    data2: 'Hello From Data2'
}

另一种选择是使用"in"-keyword检查对象上的字段,但这会导致很多样板代码,因为每次更改界面时都必须对其进行更新。

interface B1
{
    data1: string;
    data: string;
}

interface B2
{
    data2: string;
    data: string;
}

var b3: B1|B2 = {
    data: 'Hello From Data',
    data1:'Hello From Data1',
    data2:'Hello From Data2'
}

console.log(b3.data); //this field is common in both interfaces and does not need a check

if('data1' in b3) //check if 'data1' is on object
{
    console.log(b3.data1);
}
if('data2' in b3){
    console.log(b3.data2); //check if 'data2' is on object
}

答案 2 :(得分:0)

或者,您也可以只定义一个接口而不是两个

LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)

LOCAL_MODULE := app
LOCAL_WHOLE_STATIC_LIBRARIES := native

include $(BUILD_SHARED_LIBRARY)

include $(LOCAL_PATH)/ip/Android.mk
include $(LOCAL_PATH)/nativeinterface/Android.mk
include $(LOCAL_PATH)/libusb_saki4510t/Android.mk