1

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!
1
  • 1
    Sorry, I've fixed up my typos! Commented Dec 19, 2022 at 22:52

1 Answer 1

2

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

Sign up to request clarification or add additional context in comments.

1 Comment

I actually have already solved the dot notated part :)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.