With all your help I finally find a satisfying solution!
In the end it is pretty easy.
- Set default values in the properties section of the class definition
 - Define the NameValue arguments in the arguments section of the constructor
 - Only set the property if the NameValue pair is present in the NameValue struct
 
By doing so you get rid of the need to redundantly define the default value by simultaneously not cluttering the code to much.
classdef ErrorReportHandler < handle
    properties
        emailAddress string {mustBeTextScalar}              = ""
        hWriteFunc {mustBeA(hWriteFunc,"function_handle")}  = @(x) []
        nDebugLogHistory (1,1) double {mustBeFinite}        = 10
    end
    methods
        function obj = ErrorReportHandler(NameValueArgs)
            % Use Name-Value arguments to set properties
            arguments
                NameValueArgs.emailAddress
                NameValueArgs.hWriteFunc
                NameValueArgs.nDebugLogHistory
            end
            % Set name value pair properties
            assignNameValuePair(obj,NameValueArgs,"emailAddress"); % Use this syntax if you have handle class
            obj = assignNameValuePair(obj,NameValueArgs,"hWriteFunc"); % Use this syntax if you have a handle class or a value class
            obj = assignNameValuePair(obj,NameValueArgs,"nDebugLogHistory");
        end
    end
end
function obj = assignNameValuePair(obj,NameValueArgs,Name)
if isfield(NameValueArgs,Name)
    obj.(Name) = NameValueArgs.(Name);
end
end
PS: If the class is a handle class (like it is here) you can even get rid of the obj = ... part of the property assignment. I just left it there for the others using this on value classes.
Thanks to all of you for your great support on the way to the solution!

