Skip to content

Latest commit

 

History

History
169 lines (127 loc) · 8.55 KB

type-value-space.md

File metadata and controls

169 lines (127 loc) · 8.55 KB

Item 8: Know How to Tell Whether a Symbol Is in the Type Space or Value Space

Things to Remember

  • Know how to tell whether you're in type space or value space while reading a TypeScript expression. Use the TypeScript playground to build an intuition for this.
  • Every value has a static type, but this is only accessible in type space. Type space constructs such as type and interface are erased and are not accessible in value space.
  • Some constructs, such as class or enum, introduce both a type and a value.
  • typeof, this, and many other operators and keywords have different meanings in type space and value space.

Code Samples

interface Cylinder {
  radius: number;
  height: number;
}

const Cylinder = (radius: number, height: number) => ({radius, height});

💻 playground


function calculateVolume(shape: unknown) {
  if (shape instanceof Cylinder) {
    shape.radius
    //    ~~~~~~ Property 'radius' does not exist on type '{}'
  }
}

💻 playground


type T1 = 'string literal';
const v1 = 'string literal';
type T2 = 123;
const v2 = 123;

💻 playground


interface Person {
  first: string;
  last: string;
}
const jane: Person = { first: 'Jane', last: 'Jacobs' };
//    ――――           ――――――――――――――――――――――――――――――――― Values
//          ―――――― Type

💻 playground


function email(to: Person, subject: string, body: string): Response {
  //     ――――― ――          ―――――――          ――――                    Values
  //               ――――――           ――――――        ――――――   ―――――――― Types
  // ...
}

💻 playground


class Cylinder {
  radius: number;
  height: number;
  constructor(radius: number, height: number) {
    this.radius = radius;
    this.height = height;
  }
}

function calculateVolume(shape: unknown) {
  if (shape instanceof Cylinder) {
    shape
    // ^? (parameter) shape: Cylinder
    shape.radius
    //    ^? (property) Cylinder.radius: number
  }
}

💻 playground


type T1 = typeof jane;
//   ^? type T1 = Person
type T2 = typeof email;
//   ^? type T2 = (to: Person, subject: string, body: string) => Response

const v1 = typeof jane;  // Value is "object"
const v2 = typeof email;  // Value is "function"

💻 playground


const first: Person['first'] = jane['first'];  // Or jane.first
//    ―――――                    ――――――――――――― Values
//           ―――――― ―――――――                  Types

💻 playground


type PersonEl = Person['first' | 'last'];
//   ^? type PersonEl = string
type Tuple = [string, number, Date];
type TupleEl = Tuple[number];
//   ^? type TupleEl = string | number | Date

💻 playground


function email(options: {to: Person, subject: string, body: string}) {
  // ...
}

💻 playground


function email({
  to: Person,
  //  ~~~~~~ Binding element 'Person' implicitly has an 'any' type
  subject: string,
  //       ~~~~~~ Binding element 'string' implicitly has an 'any' type
  body: string
  //    ~~~~~~ Binding element 'string' implicitly has an 'any' type
}) { /* ... */ }

💻 playground


function email(
  {to, subject, body}: {to: Person, subject: string, body: string}
) {
  // ...
}

💻 playground