The class is:
class Test<P> {
constructor(data: P) {}
}
I hope the following code does not pass the type check because it has no incoming generic:
new Test({ a: 1 })
I know that the generic P above is automatically derived as {a: number}
, but this is not what I want, the following is.
new Test< {a: number} >({ a: 1 })
I tried a lot of methods, but in the end the generic P will be automatically derived into the constructor's parameter type.
A generic type is declared by specifying a type parameter in an angle brackets after a type name, e.g. TypeName<T> where T is a type parameter.
Generics can be implemented in C++ using Templates. Template is a simple and yet very powerful tool in C++. The simple idea is to pass data type as a parameter so that we don't need to write the same code for different data types. For example, a software company may need sort() for different data types.
There is a question that deals with a very similar issue here:
async function get<U = void>(url: string & (U extends void ? "You must provide a type parameter" : string)): Promise<U> {
return null as any;
}
The difference is that in that case the type parameter was not used in the parameters at all. This means typescript had no place to infer it the type parameter from. If, as in your case the type parameter is used in the argument list, typescript will use the argument as a source to infer the type parameter from and our trick of using the default value as a signal that no type parameter was explicitly specified will not work (since typescript not use the default if it can infer the type parameter).
The solution is simple enough, let typescript know that we don't want it to infer T
from a specific parameter. While there is no builtin support to do this jcalz offers a reasonable workaround here
type NoInfer<T> = [T][T extends any ? 0 : never];
class Test<P = void> {
constructor(data: NoInfer<P> & (P extends void ? "No type parameter was supplied" : {})) {}
}
new Test({ a: " "}) // err Argument of type '{ a: string; }' is not assignable to parameter of type 'void & "No type parameter was supplied"'.
new Test<{ a: string }>({ a: " "})// ok
play
To update this for TypeScript 3.8.3 you can simplify this:
type NoInfer<T> = [T][T extends unknown ? 0 : never];
// Usage in a class:
class Test<P = "No type parameter was supplied"> {
constructor(data: NoInfer<P>) {}
}
new Test({ a: " "}) // err Argument of type '{ a: string; }' is not assignable to parameter of type '"No type parameter was supplied"'.
new Test<{ a: string }>({ a: " "})// ok
// Usage in a function:
function Foo<P = "No type parameter was supplied"> (
data: NoInfer<P>
) {
return undefined
}
Play
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With