I came across a weird Typescript error while reworking module registration code in my app.
abstract class Component<P, S> {
state?: Readonly<S>;
props?: P;
}
interface IModuleProperties {
name: string;
}
interface IModuleState {
index: number;
}
export class ModuleBase<P extends IModuleProperties, S extends IModuleState> extends Component<P, S> {
}
export class Module1 extends ModuleBase<IModuleProperties, IModuleState> {
}
const t: typeof ModuleBase = Module1;
const t2: typeof ModuleBase<?,?> = Module1;
Here's the TS playground for this example.
You can see that there's an error for variable t
Type 'typeof Module1' is not assignable to type 'typeof ModuleBase'.
Construct signature return types 'Module1' and 'ModuleBase<P, S>' are incompatible.
The types of 'state' are incompatible between these types.
Type 'Readonly<IModuleState> | undefined' is not assignable to type 'Readonly<S> | undefined'.
Type 'Readonly<IModuleState>' is not assignable to type 'Readonly<S>'.(2322)
which doesn't make much sense to me given that the type parameters are hard coded in Module1
.
By accident I found the approach used for variable t2
and I'm surprised this actually works (using TS 4.9.3). This reminds me a bit on Java generics, however I could not find a description for this feature in the Typescript Generics Documentation.
So I wonder, how this feature is officially named (ignored type parameters?) and where I can find documentation for it?
CodePudding user response:
There is no such feature in TypeScript. You've encountered a bug where instantiation expressions apparently allow JSDoc type hints, but they shouldn't; see microsoft/TypeScript#51802. I filed this issue today, and the TS team has already merged microsoft/TypeScript#51804 to fix it. That means it will break starting with the next nightly build, and be released with TypeScript 5.0 at the latest, so you shouldn't keep using it. Since the ?
is apparently being interpreted as the any
type in your example code anyway, you can change ?
to any
to keep it working the same way.
That's the answer to the question as asked. It's possible that your underlying use case would be better solved with something other than any
, but that would be out of scope for this question.