'Typescript generic type constraint with conditional type, avoid circular type constraint
Suppose the following example class
class X<T> {
constructor(readonly t: Extract<'a' | 'b', T>) {}
}
The point is that the type function Extract
turns out never
if the constuctor is called with a wrong parameter, like in
const x = new X('z');
The Problem: The compiler puts a squiggle below 'z'
telling that it is not assignable to never
. Hovering over X(
in vscode only tells us that that the parameter of the constructor should be never
. There seems to be no indication that the type constraint is actually Extract(...)
.
Question: The error message on the "z"
as the constructor parameter saying it should be never
is not very helpful when you not also have the class definition in front of you. Is there a way to rephrase the definition of class X
such that we better see why the "z"
is a wrong parameter.
What I tried: First I had the type constraint on the generic parameter:
// THIS DOES NOT WORK
class X<T extends Extract<'a' | 'b', T> { ... }
Yet, this is not allowed due to a circular type reference.
Note: Extract
is only used as an example. It could be any more elaborate type function that may return never
for the actual type parameter. The actual type constraint I would like to use is the TrueStringLiterals constraint.
Solution 1:[1]
You can cook your own error messages
type IsAOrB<T> =
T extends Extract<'a' | 'b', T> ? T
: Constraint<`Extract<'a' | 'b', T>`>;
type Constraint<Message> = { [constraint]: Message };
declare const constraint: unique symbol;
class X<T> {
constructor(readonly t: IsAOrB<T>) {}
}
const x = new X('z');
// ---
// Argument of type 'string' is not assignable to
// parameter of type 'Constraint<"Extract<'a' | 'b', T>">'
The idea is that no type will match { [constraint]: Message }
because constraint
is a unique symbol, so it's functionally similar to returning never
but you have your custom message.
I would like to add that it's not super clear what your use case was meant to represent and I don't necessarily advise to do this in the general case, but this pattern is pretty handy for rejecting inputs with a custom error.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 |