Search code examples
typescriptstringvalidationsplit

Typescript split string and validate type


Let's say i have a string value of ReplaceText::some.other.property, I'd like to split this value by the delimeter of :: and validate the types of each input

type Action = 'ReplaceText' | 'ReplaceImage';

type Split<S extends string, D extends string> =
    string extends S ? Action[] :
    S extends '' ? [] :
    S extends `${infer T}${D}${infer U}` ? [T, ...Split<U, D>] : [S];
    

declare function translate<P extends string>(path: P): Split<P, '::'>;
const [action, dotString] = translate('ReplaceText::some.other.property');

This returns the values, but action is not of type of Action, I'm not quite sure where to begin here!

eg, if i did:

const [action, dotString] = translate('ActionThatDoesNotExist::some.other.property');
// id expect validation errors because this action does not exist!

Solution

  • You just need to use a string literal type like:

    type Action = 'ReplaceText' | 'ReplaceImage';
    type ActionWithPath = `${Action}::${string}`
    

    Now ActionWithPath is any string that starts with an Action, followed by :: and then any string.

    Then just use that type as your constraint:

    declare function translate<P extends ActionWithPath>(path: P): Split<P, '::'>;
    

    And the rest works like you expect:

    translate('ReplaceText::some.other.property'); // fine
    translate('ActionThatDoesNotExist::some.other.property'); // error
    

    See playground


    Note: deriving a dotted object path is much trickier and out of scope of this question, but you can start here: Typescript: deep keyof of a nested object