Skip to content

Derive boilerplate type guards for unknown types #26078

@mikeplus64

Description

@mikeplus64

Search Terms

validate
reflect
assert
unknown

Suggestion

TypeScript 3 adds an unknown type that must be inspected to be (safely) cast to another type. This manual type-checking code however is just boilerplate; it's easy to get wrong, easy to miss parts, and IMO adds absolutely no value for the programmer to have to type themselves. This boilerplate should be derivable for any non-function type, and several projects exist already that do this (or more); e.g., flow-runtime and io-ts.

This is a limited version of #1573 which suggested blanket runtime type-checking. I am suggesting a builtin operator like as that takes x: unknown as its first argument, a type T as its second, and produces x is T. Call this operator is, maybe.

Also desirable would be for error messages documenting why an unknown value does not validate; e.g. val does not have fields { x: number, y: number }. So the second part of this proposal is for a separate operator is! that is identical to is but throws a TypeError upon a type error.

I think that now that there is an unknown type, where its only use is for users to write mechanically derivable boilerplate to cast it to a known type, this is the logical next step.

I do not believe this is in opposition to the non-goal of adding/relying on runtime type-information. This only adds an extremely limited type reflection mechanism, motivated only by reducing boilerplate.

Use Cases

Any input data that's unknown; e.g. the output of a HTTP endpoint, or a websocket, some user input, JSON.parse, etc.

Examples

type Message
  = { type: 'ping', time: number }
  | { type: 'pong', time: number };

function onreceive(data: unknown) {
  if (data is Message) {
    ...
  }
}

should, roughly, generate

function onreceive(data) {
  if (typeof data === 'object' && data.type === 'ping' && typeof data.time === 'number' ||
      typeof data === 'object' && data.type === 'pong' && typeof data.time === 'number') {
    ...
  }
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    DuplicateAn existing issue was already created

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions