Conditional Types

A conditional type T extends U ? X : Y is the type-level ternary: if T is assignable to U, the result is X, otherwise Y. Inside the condition, infer Name declares a type variable that TypeScript fills in by matching. Conditional types arrived in TypeScript 2.8; since 4.1 they may refer to themselves:

Unwrapping a promise with infer, with and without distributionTypeScript
type Unwrap<T> = T extends Promise<infer V> ? Unwrap<V> : T;  // recursive
async function fetchUser(id: string) {
  const res = await fetch(`/api/users/${id}`);
  return (await res.json()) as { id: string; name: string };
}
type User = Unwrap<ReturnType<typeof fetchUser>>;  // { id: string; name: string }
const guest: User = { id: "0" };
type ToArray<T> = T extends unknown ? T[] : never;  // distributive
type ToArrayOnce<T> = [T] extends [unknown] ? T[] : never;
const mixed: ToArrayOnce<string | number> = ["a", 1];
const split: ToArray<string | number> = ["a", 1];
Output
api.ts(7,7): error TS2741: Property 'name' is missing in type '{ id: string; }' but required
  in type '{ id: string; name: string; }'.
api.ts(12,7): error TS2322: Type '(string | number)[]' is not assignable to type 'string[] |
  number[]'.
  Type '(string | number)[]' is not assignable to type 'string[]'.
    Type 'string | number' is not assignable to type 'string'.
      Type 'number' is not assignable to type 'string'.

When the checked type is a bare type parameter, the condition distributes: it runs once per union member and joins the results, so ToArray<string | number> is string[] | number[] and rejects a mixed array. Brackets, [T] extends [unknown], switch distribution off. Distribution makes filters work: the built-in Exclude<T, U> is just T extends U ? never : T, because never vanishes from a union.