5

Is it possible to make a value passed to a function be a partial string (i.e., a substring) in TypeScript

Something along the lines of this?

function transform( str: Substring<'Hello world'> ) {
    // ...
}

And when I then call the function I can pass a substring of that string

transform( 'world' );
// or
transform( 'Hello' );
// or
transform( 'ello' ); // Is valid because it exists in hello
// or
transform( 'orl' ); // Is valid because it exists in world

// Is not valid, altough individual letters exists 
// they are not in the right order
transform( 'hlowrld' ) 
5
  • What do you mean by "partial" when it comes to a string? Is it a substring? like "Hello world".includes("world")? Because one might mean that "Hlo wld" is a substring of "Hello world", and the answer here very much depends on what you're actually asking. Commented Aug 2, 2022 at 13:05
  • @jcalz Like you describe in your example, "Hello world".includes("world"). So not just individual letter, they must be in order. I thought that this was pretty obvious in the question tho. Commented Aug 2, 2022 at 13:08
  • Would a prefix/suffix type be sufficient here? Or does it necessarily have to be an includes (i.e. any position in the string) type? Commented Aug 2, 2022 at 13:10
  • 1
    "I thought that this was pretty obvious in the question tho" Obviousness is in the eye of the beholder. Would you mind editing the question to specify that you are looking for substring and not subsequence or any other possible interpretation of the term "partial"? Commented Aug 2, 2022 at 13:14
  • I edited the question, I hope this clarifies what I am trying to archieve. My native languages isn't english, so I sometimes have trouble explaining these things, sorry for that. Commented Aug 2, 2022 at 13:16

1 Answer 1

15

You could certainly make the function generic and check if T is a substring of Hello world via template literal types.

function transform<
  T extends string
>(str: "Hello World" extends `${string}${T}${string}` ? T : never) {}

transform('World')
transform('Hello')
transform('ello')
transform('orl')

transform('hlowrld') 
//         ^^^^^^^ Argument of type 'string' is not assignable to parameter of type 'never'

This can also be converted into a reusable utility type.

type Substring<
  S extends string, 
  T extends string
> = S extends `${string}${T}${string}` ? T : never

function transform<
  T extends string
>(str: Substring<"Hello World", T>) {}

Playground

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

4 Comments

Can I use your answer in my TS blog?
@captain-yossarianfromUkraine sure :)
related utility can be this, when you don't want to bind the input string early: type EndsWith<S extends string> = `${string}${S}`
For a project of my own, I needed following type: type RemovePrefix<TPrefix extends string, TString extends string> = TString extends `${TPrefix}${infer T}` ? T : never. The TPrefix is the part that should be removed from the string, and then inferred T is the result. So I can get const x: RemovePrefix<'MyPrefix/', 'MyPrefix/A' | 'MyPrefix/B'> = 'A' // or 'B'

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.