Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
156 views
in Technique[技术] by (71.8m points)

Why does TypeScript have both `void` and `undefined`?

In TypeScript, you can annotate a function as returning void:

function fn1(): void {
  // OK
}

function fn2(): void {
  // Error
  return 3;
}

You can also annotate a function to return undefined:

function fn3(): undefined {
  // OK
  return;
}

function fn4(): undefined {
  // Error
  return 3;
}

So it seems that if you call a function returning void, you'll always get back the value undefined. Yet you can't write this code:

function fn5(): void {
}
let u: undefined = fn5(); // Error

Why isn't void just an alias for undefined? Does it need to exist at all?

question from:https://stackoverflow.com/questions/58885485/why-does-typescript-have-both-void-and-undefined

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

void has special meaning in function return types, and is not an alias for undefined. Thinking of it this way is very wrong. Why?

The intent of void is that a function's return value will not be observed. This is very different from will be undefined. It's important to have this distinction so that you can properly describe functions like forEach. Let's consider a freestanding version of Array#forEach, written with undefined instead of void in the callback return position:

declare function forEach<T>(arr: T[], callback: (el: T) => undefined): void;

If you tried to use this function:

let target: number[] = [];
forEach([1, 2, 3], el => target.push(el));

You'd get an error:

Type "number" is not assignable to type "undefined"

This is a correct error - you said you wanted a function that returned the value undefined, but you actually provided a function that returned the value number because that's why Array#push returns!

Using void instead means that forEach promises not to use the return value, so it can be called with a callback that returns any value

declare function forEach<T>(arr: T[], callback: (el: T) => void): void;
let target: number[] = [];
// OK
forEach([1, 2, 3], el => target.push(el));

Why not just use any ? If you're actually the one implementing forEach, you really don't want that - having an any floating is a dangerous thing that can defeat typechecking very easily.

The corollary to this is that if you have some function expression whose return type is void, you cannot say with any certainty that the result of invoking that function is undefined.

Again, void is not an alias for undefined and an expression of type void may have any value, not just undefined

In a function body whose return type is explicitly listed as void, TypeScript will stop you from "accidently" returning a value, even though this wouldn't create a type system violation. This is helpful for catching bugs that appear from a refactoring:

// Old version
function fn(arr: number[]): void {
  const arr1 = arr.map(x => {
    return 3;
  });
}

// New version
function fn(arr: number[]): void {
  for (const x of arr) {
    // Oops, meant to do something else
    return 3;
  };
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...