3

I have the following code:

type Foo<T extends string = string> = `bar-${T}-foo`; const v: Foo = 'bar-g-foo' 

That works as expected, but it doesn't force the structure. The following is also valid:

 const v: Foo = 'bar--foo' 

How can I force the usage of T?

4
  • 2
    I was hoping type Foo<T extends string = string> = T extends "" ? never : `bar-${T}-foo`; would work (or perhaps without the default), but sadly, no. With the default, the type just ends up being string, and without the default, you have to explicitly provide the type parameter, and while doing that works, those aren't the ergonomics you want. :-| Commented May 11, 2022 at 8:13
  • why are you using the default? did you try without it? Commented May 11, 2022 at 8:17
  • As @T.J.Crowder said - "those aren't the ergonomics you want" Commented May 11, 2022 at 8:18
  • Similar question, but i don't think this is possible: stackoverflow.com/questions/66212384/… Commented May 11, 2022 at 8:39

2 Answers 2

2

The problem here is to check for an empty string. Read more about this problem here: How to write a string type that does not contain an empty string in TypeScript

Based on the stack from above you could do something like this:

type Character = 'a' | 'b' | 'c' | ... ; // Here all possible 1 letter strings type NonEmptyString = `${Character}${string}`; type Foo<T extends string = NonEmptyString> = `bar-${T}-foo`; const v: Foo = 'bar-a-foo' // ✔ const x: Foo = 'bar--foo' // ❌ Type '"bar--foo"' is not assignable to type 

Playground link

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

4 Comments

This is limited to one char
@undefined - No, it isn't: tsplay.dev/mAyZkm
The problem of course is defining that massive Character union with all the characters you want to allow, but with types only (no functions to get better inference), I don't think you'll do better than this.
I agree to @T.J.Crowder next problem now is to define an union with all single letter characters. Sadly typescript has not enough power to negate the type of Type x = "". More about this here: catchts.com/type-negation
2

It might not be the best approach, becasue of the reliance on the function assigning the value of generic type dynamically, but depending on your usage this could also be vallid

type NonEmptyString<T extends string> = T extends "" ? never : T; function fn<T extends string>(a: `bar-${NonEmptyString<T>}-foo`) { // ... } fn("bar--foo"); // Error fn("bar-g-foo"); // No error fn("bar-gg-foo"); // No error 

Playground link

1 Comment

I was struggling to come up with a function solution. Nice!

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.