Skip to content

Question / Suggestion: Behaviour of unknown in distributive conditional type. #27418

Closed
@jack-williams

Description

@jack-williams

This isn't a direct suggestion, more a query that includes a proposed alternate approach (though I'm not sure I would even want the alternate).

Search Terms

distributive conditional type unknown

Suggestion / Question

Here is the current behavior of a distributive conditional types applied to distinguished types never and unknown.

type F<T> = T extends number ? true : false;

type A = F<never>;    // never
type B = F<unknown>;  // false

A distributive conditional type maps over union elements, so the explanation for the first case has been described as:

A :: never is the empty union so we map over nothing, returning never.

Following this intuition one might assume the following:

B :: unknown is a infinite union (union of all types) so distributing always matches both sides.

Though this isn't how it actually works, and unknown is treated like a regular type and returns the false branch.

My question is: how would I go about explaining the current behavior in a way that is consistent with what never, unknown, and conditional types mean. To add to the confusion, any also has its own wildcard behavior that matches both branches (except when the extends type is any). Given than unknown has been describe as the type-safe counterpart of any, it seems like they should behave somewhat similarly in conditional types.

My suggestion / prompt for discussion is: what should unknown do? Are there any practical advantages to having it act a certain way? The only real alternate design is to have it distribute to both branches, but I'm not sure if that is 'better'.

Checklist

My suggestion meets these guidelines:

  • This wouldn't be a breaking change in existing TypeScript / JavaScript code
  • This wouldn't change the runtime behavior of existing JavaScript code
  • This could be implemented without emitting different JS based on the types of the expressions
  • This isn't a runtime feature (e.g. new expression-level syntax)

Metadata

Metadata

Assignees

No one assigned

    Labels

    QuestionAn issue which isn't directly actionable in code

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions