DEV Community

mistlog
mistlog

Posted on

4 1

Create complex type using object spread

use typetype: https://github.com/mistlog/typetype

The url parser example:

export type function parseURL = (text) => ^{
    if (parseProtocol<text> extends [infer protocol, infer rest]) {
        return {
            protocol,
            ...parseAuthority<rest>
        }
    } else {
        return never
    }
}

type function parseProtocol = (text) => ^{
    if(text extends `${infer protocol}://${infer rest}`) {
        return [
            protocol,
            rest
        ]
    } else {
        return never
    }
}

type function parseUserInfo = (text) => ^{
    if(text extends `${infer username}:${infer password}`) {
        return { username, password }
    } else {
        return { username: text }
    }
}

type function parseAuthority = (text) => ^{
    if(text extends `${infer authority}@${infer rest}`) {
        return {
            authority: parseUserInfo<authority>,
            ...parseHost<rest>
        }
    } else { 
        return {
            authority: null,
            rest: text
        }
    }
}

type function parseHost = (text) => ^{
    if(text extends `${infer name}:${infer port}`) {
        return ^{
            if(parsePort<port> extends never) {
                return never
            } else {
                return { name, port }
            }
        }
    } else {
        return { name: text }
    }
}

type function parsePort = (text) => ^{
    if(isNumberString<text> extends true) {
        return text
    } else {
        return never
    }
}

type function isNumberString = (text) => ^{
    if(text extends "") {
        return never
    } else {
        return _isNumberString<text>
    }
}

type function _isNumberString = (text) => ^{
    /* the end of recursion: each char of text is digit, no more chars to inspect */
    if(text extends "") {
        return true
    } else if(text extends `${infer digit}${infer rest}`) {
        return ^{
            if(digit extends Digit) {
                return _isNumberString<rest>
            } else {
                return false
            }
        }
    } else {
        return false
    }
}

type Digit = union ["0" , "1" , "2" , "3" , "4" , "5" , "6" , "7" , "8" , "9"]
Enter fullscreen mode Exit fullscreen mode

Then, the generated type:

export type parseURL<text> = parseProtocol<text> extends [infer protocol, infer rest] ? object$assign<{}, [{
  protocol: protocol;
}, parseAuthority<rest>]> : never;
type parseProtocol<text> = text extends `${infer protocol}://${infer rest}` ? [protocol, rest] : never;
type parseUserInfo<text> = text extends `${infer username}:${infer password}` ? {
  username: username;
  password: password;
} : {
  username: text;
};
type parseAuthority<text> = text extends `${infer authority}@${infer rest}` ? object$assign<{}, [{
  authority: parseUserInfo<authority>;
}, parseHost<rest>]> : {
  authority: null;
  rest: text;
};
type parseHost<text> = text extends `${infer name}:${infer port}` ? parsePort<port> extends never ? never : {
  name: name;
  port: port;
} : {
  name: text;
};
type parsePort<text> = isNumberString<text> extends true ? text : never;
type isNumberString<text> = text extends "" ? never : _isNumberString<text>;
type _isNumberString<text> = text extends "" ? true : text extends `${infer digit}${infer rest}` ? digit extends Digit ? _isNumberString<rest> : false : false;
type Digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9";
Enter fullscreen mode Exit fullscreen mode

test it!

import { parseURL } from "./url-parser-2";

import { Test } from "ts-toolbelt"
const { checks, check } = Test

type url = `http://admin:123456@github.com:8080`;
type result = parseURL<url>

checks([
    check<result, {
        name: "github.com";
        port: "8080";
        authority: {
            username: "admin";
            password: "123456";
        };
        protocol: "http";
    }, Test.Pass>(),
])
Enter fullscreen mode Exit fullscreen mode

SurveyJS custom survey software

JavaScript UI Libraries for Surveys and Forms

SurveyJS lets you build a JSON-based form management system that integrates with any backend, giving you full control over your data and no user limits. Includes support for custom question types, skip logic, integrated CCS editor, PDF export, real-time analytics & more.

Learn more

Top comments (0)

A Workflow Copilot. Tailored to You.

Pieces.app image

Our desktop app, with its intelligent copilot, streamlines coding by generating snippets, extracting code from screenshots, and accelerating problem-solving.

Read the docs