What you want to do is possible with a structural type system. In structural type systems, type compatibility is based on the structure of the type instead of the name (as opposed to nominal type systems).
An example in TypeScript:
interface Named {
name: string
}
class Person {
name: string
age: number
// constructor here
}
function f(obj: Named) {
// do something with obj.name
}
const joe = new Person('Joe', 25)
// Compiles, even though Person has an extra `age` field
// Person is structurally compatible with Named
f(joe)
If you pass f() a class/object that doesn't have a `name` property of type string, the compiler would catch your error.