HomeToolsAbout

Advanced Typing

typeof Type Operator

TypeScript adds a typeof operator you can use in a type context to refer to the type of a variable or property

let s = "hello"; let n: typeof s; // string

Union (|) Type

Variable can hold a value of either types defined

  • any one of several types
const varName = string | number;

varName variable can be either string type or number type

varName = "3"; // allowed varName = 3; // allowed

Intersection Types (&)

Creates a single new type by combining multiple existing types

type typeAB = typeA & typeB;
  • The typeAB will have all properties from both typeA and typeB.

When to use Union vs Intersection

If a union is an OR, then an intersection is an AND

Property Collision

When you have multiple type intersections like this example:

type MultipleIntersection = TypeA & TypeB & TypeC;

And intersection has a property that is defined multiple times of different types, you will get an error

interface TypeA { id: number; name: string; } interface TypeB { id: string; age: number; } // conflicting `id` property, will error type ErroringIntersection = TypeA & TypeB

Order of typing

Order of type intersection does not matter

type typeAB = typeA & typeB; type typeBA = typeB & typeA;

Type typeAB and typeBA have the same properties

Partial<> Type

(important) Partial type makes all fields optional on a type. If you have an identical type that requires any of the fields, two types will not be equal to each other in regards to required field

What is it

Constructs a type with all properties of passed type set to optional

  • Because all the fields become optional, the new type is considered a subset of the passed type

Using partial will fulfill the type expectation with select fields (hence, the subset)

interface Todo { title: string; description: string; } function updateTodo(todo: Todo, fieldsToUpdate: Partial<Todo>) { return { ...todo, ...fieldsToUpdate }; } // full definition const fullTodo = { title: "organize desk", description: "clear clutter", }; // partial definition, leaving out `title` property const partialTodo = updateTodo(todo1, { description: "throw out trash", });

Use cases

  1. using it as a temporary measure on unknown data type
  2. not trusting the query to return everything at once
  • e.g. not using Prisma type alone, but external type reference

When using a partial, you need a ? on an optional field that is not required in implementation

partialTypedData?.optionalField

Subset Type

Subset type is not an official feature of Typescript, but an encouraged pattern

type Subset<T extends U, U> = U; interface Foo { name: string; age: number; } type Bar = Subset< Foo, { name: string; } >;
  • this makes sure that U is a subset of T and returns U as a new type
    • You can not add new properties to Bar which are not part of Foo
    • You can not alter types in a non-compatible way. this also works recursively on nested objects

Record Type

Use Record<> for object typing

// key of string and value of string const encode_definitions: Record<string, string> = { "black": "0", "brown": "1", "red": "2", "orange": "3", "yellow": "4", "green": "5", "blue": "6", "violet": "7", "grey": "8", "white": "9" }; // key of string and any value (more common) const some_definitions: Record<string, any> = { "key_one": { "some value" }, "key_two": 2, "key_three": "some other value", }; // using another type as keys options type Choices = 'cat' | 'dog' | 'lizard'; type Pets = Record<Choices, number>; const petPrices: Pets = { cat: 4.41, dog: 8.63, lizard: 13.29, };

JSON Typing

// In Prisma Prisma.JsonValue // TS export type JSONType = { name: string; json: string; type: string; size: number; }; export type JsonValue = | string | number | boolean | null | JsonObject | JsonArray; export interface JsonObject extends Record<string, JsonValue> {} export interface JsonArray extends Array<JsonValue> {}
AboutContact