简体   繁体   中英

A way to disable “type argument inference” in generics?

I was hoping that giving a default value to a generic will take precedence over type inference, but it doesn't:

// 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

Is there a way to make sure an error is thrown if generic is not provided?

Typescript version: 3.5.2

I don't understand the use case, since disabling behavior that TypeScript users expect is probably going to cause confusion. But you're the boss.

There is an existing GitHub suggestion to allow a developer to indicate that a particular use of a generic type parameter should not be used for inference. There is no official support for this, but I think we can simulate it by taking advantage of the compiler's behavior when looking at conditional types that depend on an unresolved generic type parameter:

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

That is essentially a no-op on T , since any value you plug in (say string ) will come out the other side: [string][string extends any ? 0 : never] [string][string extends any ? 0 : never] becomes [string][0] becomes string . But the compiler sees T extends any and decides to defer the calculation until after T gets resolved. In particular, it can't use the value to infer T from that.

So then we can try

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

And see how it behaves:

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

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

The first two cases work as you want because specifying Num gives T a definite value, and NoInfer<Num> is just Num . In the last case, the compiler really has no viable inference site for T and thus it has to fall back to the default never , and you get your desired error.

Link to code

So that works as you want, but remember that you might want to rethink this idea, since people who get that error might be confused about what the heck they're supposed to do to make the error go away. People rely on type inference, so you'll need some great documentation if you proceed with this.

Anyway, hope that helps; good luck!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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