Your
<p id="demo">
  <script>
    document.write(typeWriter());
  </script>
</p>
inserts the return value of calling typeWriter into that #demo element - but the function does not return anything.
There's no real good reason to use document.write anyway. All you need to do is call the function, not use document.write as well.
var i = 0;
var txt = 'Christmas Family Service - Sunday 19th December at 11:45 am.  Come along to Bethany Evangelical Church and find out about the real meaning of Christmas.'; /* The text */
var speed = 50; /* The speed/duration of the effect in milliseconds */
function typeWriter() {
  if (i < txt.length) {
    document.getElementById("demo").innerHTML += txt.charAt(i);
    i++;
    setTimeout(typeWriter, speed);
  }
}
typeWriter();
<div class="announce">
  <p id="demo"></p>
</div>
 
 
Fixing other parts of the code:
- You only need to select the element once, not every time the loop runs
- .innerHTMLshould only be used when deliberately inserting HTML markup - with plain text,- .textContentis faster, safer, and more predictable
let i = 0;
const txt = 'Christmas Family Service - Sunday 19th December at 11:45 am.  Come along to Bethany Evangelical Church and find out about the real meaning of Christmas.'; /* The text */
const speed = 50; /* The speed/duration of the effect in milliseconds */
const demo = document.getElementById("demo");
function typeWriter() {
  if (i < txt.length) {
    demo.textContent += txt[i];
    i++;
    setTimeout(typeWriter, speed);
  }
}
typeWriter();
<div class="announce">
  <p id="demo"></p>
</div>