在TypeScript中以类型安全的方式调用函数

时间:2018-08-23 21:05:17

标签: typescript

我认为一个例子值一千字,所以下面是我想做的事情:

RewriteCond %{HTTP_REFERER} !^https://(www.)?sciami.com/ [NC]

如果将其输入到TypeScript游乐场或编译器中,则会出现错误:

type Message = keyof MessageArguments;

type MessageArguments = {
    'foo': []
    'bar': {}
};

type MsgEvent<T extends Message> = {
  data: {
    type: T
    arguments: MessageArguments[T]
  }
};

type FunctionTypes = {
    [K in Message]: (event: MsgEvent<K>) => void 
}

const functions: FunctionTypes = {
    'bar': (event) => {
        console.log("invoked bar", event);
    },

    'foo': (event) => {
        console.log("invoked foo", event);
    }

};

function is<T extends Message>(e: MsgEvent<T>, type: T): e is MsgEvent<T> {
    return e.data.type === type;
}

function invoke<T extends Message>(e: MsgEvent<T>, type: T): FunctionTypes[T] {
    if (is(e, type)) {
        return functions[e.data.type](e);
    } else {
        throw "failed to find function";
    }
}

invoke({
    data: {
        type: 'foo',
        arguments: []
    }
}, 'foo');

但是您可以从代码中清楚地知道只能调用一个方法(或不调用任何方法),而且我认为该类型应该可以表示该方法,但是我不知道如何……这几乎就像我需要告诉编译器在Cannot invoke an expression whose type lacks a call signature. Type '((event: MsgEvent<"foo">) => void) | ((event: MsgEvent<"bar">) => void)' has no compatible call signatures. (property) type: T extends "foo" | "bar" 中,function invoke<T extends Message>是互斥或-只能是值之一,而不能是两者之一。

1 个答案:

答案 0 :(得分:0)

根据Titian Cernicova-Dragomir所说的内容,编译器不知道您不是用invoke来调用T = "foo" | "bar"。因此,它只能基于T的约束"foo" | "bar"进行推理。编辑:我刚刚更新了an existing suggestion of mine,以涵盖约束类型变量单例;我建议你投票。