简体   繁体   English

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

[英]Invoking a function in type-safe way in TypeScript

I think an example is worth a thousand words, so below is what I am trying to do: 我认为一个例子值一千字,所以下面是我想做的事:

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');

If you input it into TypeScript playground or compiler you'll get an error: 如果将其输入到TypeScript游乐场或编译器中,则会出现错误:

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"

But you can clearly tell from the code that only method (or none) can be invoked, and I think the type should be able to represent that, but I don't know how... It's almost like I need to tell the compiler that in function invoke<T extends Message> , T is an exclusive or - it can only be one of the values, not either. 但是您可以从代码中清楚地知道只能调用一个方法(或不调用任何方法),而且我认为类型应该可以表示该方法,但是我不知道如何...就像我需要告诉编译器一样在function invoke<T extends Message>T是互斥或-只能是值之一,而不能是两者之一。

Along the lines of what Titian Cernicova-Dragomir said, the compiler does not know that you aren't calling invoke with T = "foo" | "bar" 按照Titian Cernicova-Dragomir所说的,编译器不知道您不是用T = "foo" | "bar"调用invoke T = "foo" | "bar" T = "foo" | "bar" . T = "foo" | "bar" Thus, it can only reason based on T 's constraint "foo" | "bar" 因此,它只能基于T的约束"foo" | "bar"推理"foo" | "bar" "foo" | "bar" . "foo" | "bar" Edit: I have just updated an existing suggestion of mine to cover constraining type variables singleton; 编辑:我刚刚更新的现有建议,以涵盖约束类型变量单例; I suggest you vote for it. 我建议你投票。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM