Browser query strings become small typed records before application code uses them.

query record Parsing a query string into a record separates raw browser text from typed application data.

URL Query Shape

pageText
query.ts
Replay: real traced execution (multi-file project)
type QueryShape = {
    page: number;
    filter: string;
};

function readQuery(raw: string): QueryShape {
    const pairs: string[] = raw.replace(/^\?/, "").split("&");
    const values: Record<string, string> = {};

    for (const pair of pairs) {
        const [key, value] = pair.split("=");
        values[key] = value;
    }

    return {
        page: Number(values.page),
        filter: values.filter
    };
}

const pageText: string = "2";
const rawQuery: string = `?page=${pageText}&filter=active`;
const query: QueryShape = readQuery(rawQuery);

console.log(`${query.filter}:${query.page + 1}`);
type QueryShape = {
    page: number;
    filter: string;
};

function readQuery(raw: string): QueryShape {
    const pairs: string[] = raw.replace(/^\?/, "").split("&");
    const values: Record<string, string> = {};

    for (const pair of pairs) {
        const [key, value] = pair.split("=");
        values[key] = value;
    }

    return {
        page: Number(values.page),
        filter: values.filter
    };
}

const pageText: string = "5";
const rawQuery: string = `?page=${pageText}&filter=active`;
const query: QueryShape = readQuery(rawQuery);

console.log(`${query.filter}:${query.page + 1}`);
  1. pageText ← 2, rawQuery ← ?page=2&filter=active

    18    };19}2021const pageText→ 2: string = "2";  //@pageText="5"22const rawQuery→ ?page=2&filter=active: string = `?page=${pageText2}&filter=active`;23const query: QueryShape = readQuery(rawQuery?page=2&filter=active);
  2. pairs ← page=2,filter=active, values ← [object Object], key ← filter

    3    filter: string;4};56function readQuery(raw?page=2&filter=active: string): QueryShape {7    const pairs→ page=2,filter=active: string[] = raw?page=2&filter=active.replace(/^\?/, "").split("&");8    const values→ [object Object]: Record<string, string> = {};910    for (const pair of pairs) {11        const [key→ filter, value→ active] = pairfilter=active.split("=");12        values[key] = valueactive;13    }1415    return {16        page: Number(values.page2),17        filter: values.filteractive18    };19}
    values this stepactivevalues[key]
  3. query ← [object Object], query.page ← 2

    21const pageText: string = "2";  //@pageText="5"22const rawQuery: string = `?page=${pageText}&filter=active`;23const query→ [object Object]: QueryShape = readQuery(rawQuery?page=2&filter=active);2425console.log(`${query.filteractive}:${query.page→ 2 + 1}`);
    outputactive:3
  1. pageText ← 5, rawQuery ← ?page=5&filter=active

    18    };19}2021const pageText→ 5: string = "5";22const rawQuery→ ?page=5&filter=active: string = `?page=${pageText5}&filter=active`;23const query: QueryShape = readQuery(rawQuery?page=5&filter=active);
  2. pairs ← page=5,filter=active, values ← [object Object], key ← filter

    3    filter: string;4};56function readQuery(raw?page=5&filter=active: string): QueryShape {7    const pairs→ page=5,filter=active: string[] = raw?page=5&filter=active.replace(/^\?/, "").split("&");8    const values→ [object Object]: Record<string, string> = {};910    for (const pair of pairs) {11        const [key→ filter, value→ active] = pairfilter=active.split("=");12        values[key] = valueactive;13    }1415    return {16        page: Number(values.page5),17        filter: values.filteractive18    };19}
    values this stepactivevalues[key]
  3. query ← [object Object], query.page ← 5

    21const pageText: string = "5";22const rawQuery: string = `?page=${pageText}&filter=active`;23const query→ [object Object]: QueryShape = readQuery(rawQuery?page=5&filter=active);2425console.log(`${query.filteractive}:${query.page→ 5 + 1}`);
    outputactive:6