properties
Properties gained, lost and changed, for an object type (or a value of one).
import { change, FLAGS } from "#codebase/tcmts/cli/semver_checks"; import type { LintId } from "#codebase/tcmts/cli/semver_checks"; import type { TypeChecker } from "#codebase/tcmts/core/ts"; import { SymbolFlags as ts_SymbolFlags } from "typescript/sync"; import type { Symbol as ts_Symbol, Type as ts_Type } from "typescript/sync"; export function properties(checker: TypeChecker, ot: ts_Type, nt: ts_Type, add: (l: LintId, d?: string) => void) { const str = (t: ts_Type) => checker.typeToString(t, undefined, FLAGS); const optional = (s: ts_Symbol) => !!(s.flags & ts_SymbolFlags.Optional); const readonly = (s: ts_Symbol) => checker.isReadonlySymbol(s); const before = new Map(checker.getPropertiesOfType(ot).map((s) => [s.name, s])); const after = new Map(checker.getPropertiesOfType(nt).map((s) => [s.name, s])); for (const [name, s] of before) { const t = after.get(name); if (!t) { add("type_property_removed", name); continue; } if (!optional(s) && optional(t)) add("type_property_made_optional", name); if (optional(s) && !optional(t)) add("type_property_made_required", name); if (!readonly(s) && readonly(t)) add("type_property_made_readonly", name); if (readonly(s) && !readonly(t)) add("type_property_made_writable", name); const [x, y] = [checker.getTypeOfSymbol(s), checker.getTypeOfSymbol(t)]; if (!checker.isTypeAssignableTo(x, y) || !checker.isTypeAssignableTo(y, x)) add("type_property_type_changed", change(`${name}: `, str(x), str(y))); } for (const [name, t] of after) if (!before.has(name)) add(optional(t) ? "type_optional_property_added" : "type_required_property_added", name); }
uses
- tcmts.cli.semver_checks.FLAGS
- tcmts.cli.semver_checks.LintId
- tcmts.cli.semver_checks.change
- tcmts.core.ts.TypeChecker