Item 8: Know How to Tell Whether a Symbol Is in the Type Space or Value Space
May 10, 2024 ยท View on GitHub
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
typeandinterfaceare erased and are not accessible in value space. - Some constructs, such as
classorenum, 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});
function calculateVolume(shape: unknown) {
if (shape instanceof Cylinder) {
shape.radius
// ~~~~~~ Property 'radius' does not exist on type '{}'
}
}
type T1 = 'string literal';
const v1 = 'string literal';
type T2 = 123;
const v2 = 123;
interface Person {
first: string;
last: string;
}
const jane: Person = { first: 'Jane', last: 'Jacobs' };
// โโโโ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ Values
// โโโโโโ Type
function email(to: Person, subject: string, body: string): Response {
// โโโโโ โโ โโโโโโโ โโโโ Values
// โโโโโโ โโโโโโ โโโโโโ โโโโโโโโ Types
// ...
}
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
}
}
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"
const first: Person['first'] = jane['first']; // Or jane.first
// โโโโโ โโโโโโโโโโโโโ Values
// โโโโโโ โโโโโโโ Types
type PersonEl = Person['first' | 'last'];
// ^? type PersonEl = string
type Tuple = [string, number, Date];
type TupleEl = Tuple[number];
// ^? type TupleEl = string | number | Date
function email(options: {to: Person, subject: string, body: string}) {
// ...
}
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
}) { /* ... */ }
function email(
{to, subject, body}: {to: Person, subject: string, body: string}
) {
// ...
}