The core problem here is that you don't actually want to check if something is an object, but whether it matches the Human type. The correct way to do that is to define a type guard [0], for example:
function isHuman(input: any): input is Human {
return (
Boolean(input) &&
Object.prototype.hasOwnProperty.call(input, "name") &&
Object.prototype.hasOwnProperty.call(input, "age")
);
}
There are libraries which can automate this for you which is the route I would recommend if you need to do this often. As you can see, the code to cover all edge cases such as `Object.create(null)` etc is not trivial.
That's fairly subjective and I can see arguments for both sides, in the above example I've gone with the approach the Typescript documentation itself gives which uses any. Given the parameter is only used as an input, using any and unknown are interchangeable and there is no difference in this specific case.
While I see where you're coming from, semantic formulation like this is highly subjective. All the same the problem statement could be "Given any kind of input, tell me whether it's a Human or not".
This approach is "correct" only when you're interacting with an API you have no control over whatsoever because specifying all this and maintaining it is really error prone.
All this boilerplate is not a proof. It remains an assertion. And so in most cases you might as well just add a "type"/"kind" property to your object (or create a class).
Personally I really enjoy Typanion [0] since it's very similar to Yup [1] which I previously had extensive experience with. You can find more alternatives and a lengthy discussion about the whole problem space and its history in [2].
[0] https://www.typescriptlang.org/docs/handbook/advanced-types....