I know you already have some good answers but SQL_VARIANT_PROPERTY I think has been misunderstood.
You use SQL_Variant_Property with a column and then an indication what you want on it's metadata property. However if it is null it does not tell you much.
EG:
declare
@Start date = getdate()
, @End datetime= getdate()
, @Int int = 1
, @DateNull date
;
select
sql_variant_property(@Start, 'BaseType')
, sql_variant_property(@End, 'BaseType')
, sql_variant_property(@Int, 'BaseType')
, sql_variant_property(@DateNull, 'BaseType')
Will return three datatypes and a null. Handling NULL is a big part of SQL. A great many people, myself included, at times want to handle null with a value to represent it or else at other times not care. SQL Variant ONLY WORKS for a populated value with the argument: 'BaseType', else it will return a null. As far as I know this is due to SQL saying: "You have no data here, nothing to determine for memory use."
Generally I will specify isnull(@thing, 0) when working with integers were I explicitly want a dataset to include zeros for unknowns. At other times I may wish to have a user know a null occurrence did something else isnull(@thing, 'not present') for a report. Still other times you can use coalesce for basically an array of posibilities coalesce(@thing, @otherthing, @yetotherthing, 'unknown').
I think in the code you are witnessing someone is converting something when I am not certain of where you would really need to do such a thing. The datatype of a column in a table is maintained of what it needs to be and SQL will not store memory in it when it is NULL. So the need to change it seems arbitrary IMHO. I do know that you can handle better memory consumption when you expect more nulls with the SPARSE option that was introduced I believe in SQL 2008. But I don't know when to cast something that consumes hardly anything to be more.