I have an abstract class that looks like this:
// step.ts
import { AllowedStepNames } from "./interfaces";
abstract class Step {
abstract nextStep(): AllowedStepNames | undefined
}
Which in turn uses a type in a seperate file:
// interfaces/index.ts
const stepList = {
foo: "bar",
bar: "baz"
};
export type AllowedStepNames = keyof typeof stepList;
I have a class that extends from it that looks like this:
// referral-reason.step.ts
export default class ReferralReasonStep extends Step {
nextStep() {
return this.params.reason === 'no-reason' ? 'foo' : undefined
}
}
However, the compiler throws an error:
Property 'nextStep' in type 'NotEligibleStep' is not assignable to the same property in base type 'Step'.
However, if I add the return type in my inherited class like so:
export default class ReferralReasonStep extends Step {
nextStep(): AllowedStepNames | undefined {
return this.params.reason === 'no-reason' ? 'foo' : undefined
}
}
This seems strange to me, because I'd expect the extended class to inherit the return type from the abstract class. Can someone tell me what's going on? Or am I doing something wrong?
In addition, if I put all my classes and types in the same file, the problem goes away.
CodePudding user response:
I think I got the issue now:
TypeScript is automatically inferring the type string
instead of foo | undefined
to your function based on the return type and string
is not assignable to the union AllowedStepNames
.
What can you do to fix this?
Option 1
As you already said in the post, you can explicitly set the return type of the function to foo | undefined
.
Option 2
The reason there was no error in the TypeScript playground is a difference in the tsconfig rules. I identified strictNullChecks
to be the rule that changes this behavior. So depending on your project, you could enable this rule.
compilerOptions: {
strictNullChecks: "true"
}
Option 3
By using as const
you can tell the compiler to use the string literal value as the type instead of string
.
nextStep() {
return this.params.reason === "no-reason" ? "foo" as const : undefined;
}