最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - How do I define a typescript type with a repeating structure? - Stack Overflow

programmeradmin2浏览0评论

I have a type that looks something like this:

type Location=`${number},${number};${number},${number};...`

Is there a Utility type like Repeat<T> that can do this for me? like this:

type Location=Repeat<`${number},${number};`>

I have a type that looks something like this:

type Location=`${number},${number};${number},${number};...`

Is there a Utility type like Repeat<T> that can do this for me? like this:

type Location=Repeat<`${number},${number};`>
Share Improve this question asked Jan 15, 2022 at 4:36 hyisYoohyisYoo 1192 bronze badges 3
  • why not just give type as string – DecPK Commented Jan 15, 2022 at 4:37
  • 1 because I want to narrow my type – hyisYoo Commented Jan 15, 2022 at 4:43
  • then just declare it with const location = any_value then type will be the any_value... – DecPK Commented Jan 15, 2022 at 4:44
Add a ment  | 

5 Answers 5

Reset to default 6

IT WORKS ONLY IN TS >=4.5

It is possible to create standalone type.

Please see this example:

type Coordinates = `${number},${number};`

type MAXIMUM_ALLOWED_BOUNDARY = 50

type Last<T extends string[]> = T extends [...infer _, infer Last] ? Last : never;

type ConcatPrevious<T extends any[]> = Last<T> extends string ? `${Last<T>}${Coordinates}` : never

type Mapped<
    N extends number,
    Result extends Array<unknown> = [Coordinates],
    > =
    (Result['length'] extends N
        ? Result
        : Mapped<N, [...Result, ConcatPrevious<Result>]>
    )


// type MyLocation = 
// | `${number},${number};` 
// | `${number},${number};${number},${number};` 
// | `${number},${number};${number},${number};${number},${number};` 
// | `${number},${number};${number},${number};${number},${number};${number},${number};` 
// | `${number},${number};${number},${number};${number},${number};${number},${number};${number},${number};` 
// | ... 44 more ... 
// | `${number},${number};${number},${number};${number},${number};${number},${number};${number},${number};${number},${number}; ....

type MyLocation = Mapped<MAXIMUM_ALLOWED_BOUNDARY>[number]

const myLocation1: MyLocation = '45,56;67,68;' // ok
const myLocation2: MyLocation = '45,56;67,68;1,2;3,4;5,6;7,8;9,10;' // ok
const myLocation3: MyLocation = '45,56;67,68;1,2;3,4;5,6;7,8;9,10,' // expected error

Playground

Mapped types is an utility type which represents a while loop. It iterates until length of Result will reach N. In other words Mapped<10> - will iterate 10 times. See this example in pure js:

const mapped = (N: number, Result: any[] = []): string => {
    if (N === Result.length) {
        return Result.join('')
    }
    
    const x = Math.random();
    const y = Math.random()
    return mapped(N, [...Result, `${x},${y};`])
}

It is hard to represent unions in js, thats why I have used join(''). I hope it is clear how it works.

If you want to increase MAXIMUM_ALLOWED_BOUNDARY to 500 it will heat your CPU so be careful.

As you might have noticed, it is impossible in type script to represent recursive pattern for type but it is possible to create big enough union.

Please keep in mind that there are some drawbacks of ${number} type. You are allowed to use numbers with leading zero like here:

const x: `${number}` = '01'.

Useful links:

  1. Here you can find an example how you can create a range of numbers using this pattern.

  2. Here you can find a PR where this feature was introduced

  3. Here and here you can find my articles which are related to this pattern

I don't think there is a way to define an infinite repeating pattern for a type that you use on variable declaration.

However, a type guard on a function can check that a string matches an infinite pattern, like so (playground):

type MatchesPattern<Pattern extends string, Current extends string> = Current extends `` ? string : (Current extends `${Pattern}${infer Rest}` ? MatchesPattern<Pattern, Rest> : never);

type LocationPattern = `${number},${number};`;

declare function onlyAcceptsLocation<L extends string & IsLocation, IsLocation = MatchesPattern<LocationPattern, L>>(location: L): void;

onlyAcceptsLocation("12,34;56,78;"); // 
发布评论

评论列表(0)

  1. 暂无评论