- Home
- Skills
- Yanko Belov
- Code Craft
- Liskov Substitution
liskov-substitution_skill
- TypeScript
6
GitHub Stars
1
Bundled Files
2 months ago
Catalog Refreshed
4 months ago
First Indexed
Readme & install
Copy the install command, review bundled files from the catalogue, and read any extended description pulled from the listing source.
Installation
Preview and clipboard use veilstrat where the catalogue uses aiagentskills.
npx veilstrat add skill yanko-belov/code-craft --skill liskov-substitution- SKILL.md6.8 KB
Overview
This skill teaches and enforces the Liskov Substitution Principle (LSP) for TypeScript codebases. It helps you decide when inheritance is wrong, when to replace subclassing with interfaces or composition, and how to avoid overrides that throw, no-op, or change semantics. The goal is safer, more predictable polymorphism and fewer runtime surprises.
How this skill works
It inspects class hierarchies and overridden methods to flag violations where a subtype cannot safely replace its base type. It highlights override smells: throwing errors, no-op implementations, and semantic changes that break callers. It recommends design patterns: separate capability interfaces, composition, and distinct types instead of forced inheritance.
When to use it
- When creating a class that extends another class or implements an interface
- Before overriding methods inherited from a parent class
- If you feel tempted to throw exceptions or implement no-ops in overrides
- When an inheritance hierarchy feels forced or brittle
- When callers behave differently using specific subclasses
Best practices
- Prefer small capability interfaces (e.g., Flyable, Readable, Writable) over broad base classes
- Use composition to share behavior instead of inheriting incompatible contracts
- Run the substitution test: replace Parent with Child everywhere and verify correctness
- Refuse subclasses that would throw, silently no-op, or change method semantics
- Push back on requirements that mandate unsafe inheritance and propose interface-based alternatives
Example use cases
- Refactoring a Rectangle/Square relationship into separate Shape types with distinct setters
- Replacing Bird subclasses that can’t fly with a Flyable interface and non-flying Bird implementations
- Splitting storage into Readable and Writable interfaces so read-only implementations don’t inherit write methods
- Reviewing PRs to detect overrides that throw or become no-ops and advising redesign
- Designing public APIs to expose capabilities via interfaces, preventing unsafe subclassing
FAQ
Try substituting every instance of the parent type with the child type; if any behavior or assertions break, you have an LSP violation.
Is throwing in an override ever acceptable?
No—throwing in an override breaks the parent contract. Prefer redesign: remove the method from the parent, use interfaces, or use composition.