一种禁用泛型中的“类型参数推断”的方法?

时间:2019-06-20 14:00:44

标签: typescript

我希望为泛型提供默认值将优先于类型推断,但事实并非如此:

// placeholder for a real express response.send
const sendResponse =  (x) => console.log(x);

function sendResult<T = never>(send: any, result: T) {
  send(result);
}

// I want to use this always with a type
type Num = { x: number };
sendResult<Num>(sendResponse, { x: 1 });
sendResult<Num>(sendResponse, { x: 'sss' }); // correctly showing error

// When I don't supply type, I'd like an error.
// But, T gets inferred instead of defaulting to never... so, no error :-(
sendResult(sendResponse, {x: 1})

See demo

如果没有提供泛型,是否有办法确保引发错误?

打字稿版本:3.5.2

1 个答案:

答案 0 :(得分:5)

我不理解用例,因为禁用TypeScript用户期望的行为可能会引起混乱。但是你是老板。

有一个existing GitHub suggestion,使开发人员可以指示不应将通用类型参数的特定用法用于推理。对此没有官方支持,但是我认为我们可以通过利用依赖于未解析的泛型类型参数的conditional types来利用编译器的行为来对其进行仿真:

type NoInfer<T> = [T][T extends any ? 0 : never];

这实际上是对T的禁止操作,因为您插入的任何值(例如string)都会从另一端出来:[string][string extends any ? 0 : never]变成[string][0]变成string。但是编译器会看到T extends any并决定将计算推迟到T解决之后。特别是,它不能使用该值从中推断T

所以我们可以尝试

function sendResult<T = never>(send: any, result: NoInfer<T>) {
  send(result);
}

并查看其行为:

type Num = { x: number };
sendResult<Num>(sendResponse, { x: 1 }); // okay
sendResult<Num>(sendResponse, { x: "sss" }); // error

sendResult(sendResponse, { x: 1 }); // error

前两种情况可以根据需要工作,因为指定Num会给T一个确定的值,而NoInfer<Num>只是Num。在最后一种情况下,编译器确实没有T的可行推断站点,因此必须退回到默认的never,您会得到所需的错误。

Link to code

这样可以按您的意愿工作,但是请记住,您可能想重新考虑这个想法,因为遇到此错误的人可能会对应该采取什么措施使错误消失的方法感到困惑。人们依靠类型推断,因此,如果继续进行此操作,则需要一些出色的文档。

无论如何,希望能有所帮助;祝你好运!