The same concept holds true for cell array elements if they are numeric arrays.
TestCell{1}(TestCell{1} <= 2) = NaN;
Now if you want to loop through all of the elements of the cell without an explicit for loop, this is a little difficult because you can't do assignment within cellfun.
The alternative is to construct some expression which will return an array where there are NaNs when your condition is true and the original values elsewhere.
Such an expression could look like this:
x .* ~(x <= 2) ./ ~(x <= 2);
This will cause each element to be multiplied by 0/0 (NaN) when the condition is true and multiplied by 1/1 (1) when the condition is false. In this way, all values that meet the condition will be set to NaNs.
If we try this on your example data:
x = [1 2 10 45];
x .* ~(x <= 2) ./ ~(x <= 2)
NaN NaN 10 45
We get the NaN's where your condition is true. So now we can plug this into cellfun to perform this operation on all contents.
output = cellfun(@(x)x .* ~(x <= 2)./~(x <= 2), TestCell, 'uni', 0);
The alternative is to write the conditional backwards so all elements which don't meet the criteria will be set to NaN. This will prevent having to negate both of the conditionals in the above equations.
x = [1 2 10 45]
x .* (x > 2) ./ (x > 2)
And we can plug this into cellfun like we did above.
output = cellfun(@(x)x .* (x > 2) ./ (x > 2), TestCell, 'uni', 0);
The primary disadvantage of this approach is that it requires you to evaluate the conditional twice as there is no good way to store the intermediate result within cellfun. This may or may not be an issue depending upon how big each element is. There really is no shame in having a for loop for doing this sort of thing as it is likely more performant than the solution here.