TypeScript
TypeScript copied to clipboard
More specific TemplateStringsArray type for tagged templates
This introduces a more specific type over TemplateStingsArray
when invoking a tagged template. This would then allow developers to interpolate the literal types provided to the tagged template invocation, along with the provided arguments:
type Interpolate<T extends readonly string[], A extends any[], R extends string = ''> =
T extends readonly [infer TH extends string, ...infer TT extends readonly string[]] ?
A extends [infer AH extends string, ...infer AT extends string[]] ?
Interpolate<TT, AT, `${R}${TH}${AH}`> :
Interpolate<TT, [], `${R}${TH}`> :
R;
declare function interp<
T extends TemplateStringsArray,
A extends string[]
>(strs: T, ...args: A): Interpolate<T, A>;
const a = interp`a${"b"}c`; // "abc"
const b = interp`1${2}3`; // "123"
The type we manufacture for the tagged template invocation is an instantiation of TemplateStringsArrayOf<Cooked, Raw>
:
type TemplateStringsArrayOf<
Cooked extends readonly string[],
Raw extends readonly string[]
> =
Cooked & { readonly raw: Raw };
This would then allow you to perform custom interpolation against either the "cooked" values (where escapes are normalized), and "raw" values (where escapes are preserved):
declare function raw<
T extends TemplateStringsArray,
A extends string[]
>(strs: T, ...args: A): Interpolate<T["raw"], A>;
const a = raw`a\n${"b"}\nc`; // "a\\nb\\nc"
In theory, more complex interpolation could also be achieved, but that is an exercise left to the reader:
type QueryResult<T extends readonly string[], A extends any[]> =
// some type that parses T and interpolates A...
todo;
declare function query<T extends TemplateStringsArray, A extends any[]>(strs: T, ...args: A): QueryResult<T, A>;
interface Person { firstName: string, lastName: string }
declare const people: Iterable<Person>;
const result = query`
for x in ${people}
where x.firstName === ${"Bob"}
select x.lastName
`;
result; // Iterable<string>
To support interpolation over a TemplateStringsArray
, I also needed to make a change to inferFromObjectTypes
. Prior to this change you could not infer to tuple element positions if the source type was an intersection of a tuple and another type:
type X<T extends any[]> = T extends [infer H, ...infer _] ? H : never;
// before
type T1 = X<[1, 2]>; // 1 (ok)
type T2 = X<[1, 2] & { foo: true }>; // never (😞)
However, this becomes a problem when trying to pick apart a generic TemplateStringsArrayOf
type. To address this, this PR makes a small change in how we perform this inference. Nothing changes when a source type is already an array or tuple type, but if the source type is instead an intersection of an array or tuple type and another type, we will also now permit tuple element inference as long as the intersected types do not shadow tuple-specific properties (i.e., numeric indexers, numeric-stringed properties, or the "length"
property):
type X<T extends any[]> = T extends [infer H, ...infer _] ? H : never;
// after
type T1 = X<[1, 2]>; // 1 (ok)
type T2 = X<[1, 2] & { foo: true }>; // 1 (ok)
Fixes #33304 Fixes #31422 Related #29432 Related #16551
I tinkered with an example of a tail-recursive parser for jest.each
here, though it can probably be drastically simplified.
Here's a much simpler version of Jest's each
:
type IDStart =
| "a" | "b" | "c" | "d" | "e" | "f" | "g" | "h" | "i" | "j" | "k" | "l" | "m" | "n" | "o" | "p" | "q" | "r" | "s" | "t" | "u" | "v" | "w" | "x" | "y" | "z"
| "A" | "B" | "C" | "D" | "E" | "F" | "G" | "H" | "I" | "J" | "K" | "L" | "M" | "N" | "O" | "P" | "Q" | "R" | "S" | "T" | "U" | "V" | "W" | "X" | "Y" | "Z"
| "$" | "_"
;
type IDPart =
| "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"
| IDStart
;
type Trim<S extends string, Chars extends string = " " | "\t" | "\v" | "\n"> =
S extends (Chars extends "" ? S : never) ? S :
S extends `${Chars}${infer R}` ? Trim<R, Chars> :
S extends `${infer R}${Chars}` ? Trim<R, Chars> :
S;
type ParseHeaders<S extends string> =
S extends "|" ? [] :
S extends `${infer H}|${infer T}` ? [Trim<H>, ...ParseHeaders<T>] :
[Trim<S>];
type CheckHeader<TIn extends string, TWork extends string = TIn, Valid extends IDPart = IDStart> =
TWork extends `${infer Ch}${infer R}` ?
Ch extends Valid ? CheckHeader<TIn, R, IDPart> :
JestEachParseError<`Invalid identifier: '${TIn}'`> :
TIn extends '' ? JestEachParseError<`Identifier expected.`> :
TIn;
type CheckHeaders<TIn extends string[], TWork extends string[] = TIn> =
TWork extends [infer TH extends string, ...infer TT extends string[]] ?
CheckHeader<TH> extends infer E extends JestEachParseError<any> ? E :
CheckHeaders<TIn, TT> :
TIn;
type ParseRows<A extends any[], S extends readonly string[], Row extends any[] = [], Rows extends any[][] = []> =
[A, S] extends [[infer AH, ...infer AT], readonly [infer TH extends string, ...infer TT extends string[]]] ?
Trim<TH, " " | "\t" | "\v"> extends "|" ? ParseRows<AT, TT, [...Row, AH], Rows> :
Trim<TH, " " | "\t" | "\v"> extends "\n" | "" ? ParseRows<AT, TT, [], [...Rows, [...Row, AH]]> :
JestEachParseError<`Unexpected character: '${Trim<TH>}'`> :
[A, S] extends [[], readonly []] ? Rows :
JestEachParseError<`Mismatched elements`>;
type JestEachArgument<Headers extends string[] | JestEachParseError<any>, Rows extends any[][] | JestEachParseError<any>> =
Headers extends string[] ?
Rows extends any[][] ?
{
[P1 in keyof Rows]: {
[P2 in keyof Headers as P2 extends `${number}` ? Headers[P2] : never]:
P2 extends keyof Rows[P1] ? Rows[P1][P2] : undefined;
};
}[number] :
Rows :
Headers;
type JestEachFunction<Arg> =
Arg extends JestEachParseError<any> ? Arg :
(name: string, cb: (arg: Arg) => void, timeout?: number) => void;
declare const JestEachParseError: unique symbol;
interface JestEachParseError<Message extends string> {
[JestEachParseError]: Message;
}
type JestEach<T extends readonly string[], A extends any[]> =
T extends readonly [infer TH extends string, ...infer TT extends readonly string[]] ?
JestEachFunction<JestEachArgument<CheckHeaders<ParseHeaders<TH>>, ParseRows<A, TT>>> :
JestEachParseError<`Mismatched elements`>;
declare function each<T extends readonly string[], A extends (string | symbol | number | bigint | boolean | null | undefined | object)[]>(strs: T, ...args: A): JestEach<T, A>;
// jest
it.each`
foo | bar
${"a"} | ${"b"}
${"a"} | ${"c"}
`("test", ({ foo, bar }) => {
// ^? any
// ^? any
});
each`
foo | bar
${"a"} | ${"b"}
${"c"} | ${"d"}
`("test", ({ foo, bar }) => {
// ^? "a" | "c"
// ^? "b" | "d"
});
There is no longer any order dependence. The behavior for inferring from an intersection of two tuple types now falls back to pre-existing behavior.
Also, I've added a test for Jest's each
based on the example above.
@DanielRosenwasser: Are we comfortable taking this for 4.8 or would you rather wait?
@typescript-bot perf test @typescript-bot run dt @typescript-bot test this @typescript-bot user test this
Heya @rbuckton, I've started to run the parallelized Definitely Typed test suite on this PR at f8752ad296573db618861f4c4b75b60682bee682. You can monitor the build here.
Heya @rbuckton, I've started to run the perf test suite on this PR at f8752ad296573db618861f4c4b75b60682bee682. You can monitor the build here.
Heya @rbuckton, I've started to run the diff-based user code test suite on this PR at f8752ad296573db618861f4c4b75b60682bee682. You can monitor the build here.
Update: The results are in!
Heya @rbuckton, I've started to run the extended test suite on this PR at f8752ad296573db618861f4c4b75b60682bee682. You can monitor the build here.
Heya @rbuckton, I've run the RWC suite on this PR - assuming you're on the TS core team, you can view the resulting diff here.
@rbuckton Great news! no new errors were found between main..refs/pull/49552/merge
@typescript-bot perf test
Heya @rbuckton, I've started to run the perf test suite on this PR at e079811212623ee4b99b1fddcf54fb8187f41632. You can monitor the build here.
Update: The results are in!
@rbuckton The results of the perf run you requested are in!
Here they are:
Comparison Report - main..49552
Metric | main | 49552 | Delta | Best | Worst |
---|---|---|---|---|---|
Angular - node (v10.16.3, x64) | |||||
Memory used | 359,557k (± 0.02%) | 359,644k (± 0.02%) | +87k (+ 0.02%) | 359,533k | 359,779k |
Parse Time | 2.11s (± 0.63%) | 2.11s (± 0.41%) | -0.00s (- 0.05%) | 2.10s | 2.14s |
Bind Time | 0.91s (± 1.05%) | 0.90s (± 0.78%) | -0.00s (- 0.44%) | 0.89s | 0.92s |
Check Time | 5.95s (± 0.43%) | 5.99s (± 0.29%) | +0.04s (+ 0.71%) | 5.96s | 6.04s |
Emit Time | 6.11s (± 0.77%) | 6.14s (± 0.65%) | +0.03s (+ 0.49%) | 6.08s | 6.25s |
Total Time | 15.07s (± 0.45%) | 15.14s (± 0.27%) | +0.07s (+ 0.47%) | 15.07s | 15.24s |
Compiler-Unions - node (v10.16.3, x64) | |||||
Memory used | 206,384k (± 0.04%) | 206,445k (± 0.05%) | +61k (+ 0.03%) | 206,241k | 206,661k |
Parse Time | 0.84s (± 0.89%) | 0.84s (± 1.19%) | +0.00s (+ 0.00%) | 0.82s | 0.87s |
Bind Time | 0.53s (± 1.59%) | 0.53s (± 0.84%) | +0.00s (+ 0.19%) | 0.52s | 0.54s |
Check Time | 8.12s (± 1.07%) | 8.18s (± 0.52%) | +0.06s (+ 0.73%) | 8.09s | 8.26s |
Emit Time | 2.51s (± 1.05%) | 2.50s (± 0.69%) | -0.00s (- 0.08%) | 2.47s | 2.54s |
Total Time | 11.99s (± 0.85%) | 12.05s (± 0.44%) | +0.06s (+ 0.48%) | 11.95s | 12.18s |
Monaco - node (v10.16.3, x64) | |||||
Memory used | 343,744k (± 0.02%) | 343,785k (± 0.01%) | +41k (+ 0.01%) | 343,720k | 343,859k |
Parse Time | 1.59s (± 0.76%) | 1.59s (± 0.76%) | +0.01s (+ 0.50%) | 1.56s | 1.62s |
Bind Time | 0.77s (± 1.01%) | 0.77s (± 0.67%) | 0.00s ( 0.00%) | 0.76s | 0.78s |
Check Time | 5.98s (± 0.64%) | 5.95s (± 0.44%) | -0.03s (- 0.45%) | 5.89s | 6.00s |
Emit Time | 3.24s (± 0.85%) | 3.26s (± 0.73%) | +0.02s (+ 0.77%) | 3.21s | 3.34s |
Total Time | 11.57s (± 0.54%) | 11.58s (± 0.26%) | +0.00s (+ 0.03%) | 11.50s | 11.64s |
TFS - node (v10.16.3, x64) | |||||
Memory used | 305,120k (± 0.02%) | 305,158k (± 0.03%) | +38k (+ 0.01%) | 304,964k | 305,420k |
Parse Time | 1.29s (± 0.78%) | 1.29s (± 0.53%) | +0.00s (+ 0.00%) | 1.28s | 1.31s |
Bind Time | 0.73s (± 0.92%) | 0.73s (± 0.65%) | +0.00s (+ 0.00%) | 0.72s | 0.74s |
Check Time | 5.41s (± 0.59%) | 5.38s (± 0.60%) | -0.02s (- 0.44%) | 5.31s | 5.45s |
Emit Time | 3.40s (± 1.03%) | 3.44s (± 0.68%) | +0.04s (+ 1.12%) | 3.39s | 3.50s |
Total Time | 10.83s (± 0.53%) | 10.84s (± 0.28%) | +0.01s (+ 0.12%) | 10.77s | 10.91s |
material-ui - node (v10.16.3, x64) | |||||
Memory used | 469,379k (± 0.01%) | 471,939k (± 0.01%) | +2,560k (+ 0.55%) | 471,751k | 472,084k |
Parse Time | 1.85s (± 0.77%) | 1.84s (± 0.58%) | -0.00s (- 0.22%) | 1.82s | 1.87s |
Bind Time | 0.69s (± 1.34%) | 0.69s (± 1.34%) | +0.00s (+ 0.00%) | 0.67s | 0.71s |
Check Time | 14.51s (± 0.73%) | 14.62s (± 0.71%) | +0.12s (+ 0.82%) | 14.40s | 14.85s |
Emit Time | 0.00s (± 0.00%) | 0.00s (± 0.00%) | 0.00s ( NaN%) | 0.00s | 0.00s |
Total Time | 17.04s (± 0.66%) | 17.16s (± 0.58%) | +0.12s (+ 0.68%) | 16.94s | 17.36s |
xstate - node (v10.16.3, x64) | |||||
Memory used | 584,715k (± 1.67%) | 578,260k (± 0.02%) | -6,455k (- 1.10%) | 578,002k | 578,446k |
Parse Time | 2.64s (± 0.40%) | 2.63s (± 0.44%) | -0.01s (- 0.27%) | 2.61s | 2.66s |
Bind Time | 1.05s (± 0.96%) | 1.04s (± 0.97%) | -0.00s (- 0.10%) | 1.03s | 1.07s |
Check Time | 1.55s (± 0.65%) | 1.55s (± 0.62%) | +0.00s (+ 0.19%) | 1.52s | 1.56s |
Emit Time | 0.07s (± 3.14%) | 0.07s (± 0.00%) | -0.00s (- 1.41%) | 0.07s | 0.07s |
Total Time | 5.29s (± 0.36%) | 5.29s (± 0.26%) | -0.01s (- 0.13%) | 5.25s | 5.31s |
Angular - node (v12.1.0, x64) | |||||
Memory used | 337,240k (± 0.02%) | 337,315k (± 0.02%) | +75k (+ 0.02%) | 337,212k | 337,429k |
Parse Time | 2.10s (± 0.66%) | 2.10s (± 0.59%) | +0.00s (+ 0.10%) | 2.07s | 2.13s |
Bind Time | 0.86s (± 1.16%) | 0.86s (± 1.27%) | +0.00s (+ 0.23%) | 0.84s | 0.90s |
Check Time | 5.76s (± 0.60%) | 5.77s (± 0.56%) | +0.01s (+ 0.21%) | 5.70s | 5.83s |
Emit Time | 6.36s (± 0.68%) | 6.38s (± 0.68%) | +0.02s (+ 0.31%) | 6.25s | 6.49s |
Total Time | 15.08s (± 0.30%) | 15.11s (± 0.45%) | +0.04s (+ 0.25%) | 14.96s | 15.26s |
Compiler-Unions - node (v12.1.0, x64) | |||||
Memory used | 194,005k (± 0.14%) | 193,964k (± 0.16%) | -41k (- 0.02%) | 193,010k | 194,297k |
Parse Time | 0.83s (± 1.21%) | 0.84s (± 1.50%) | +0.01s (+ 1.09%) | 0.81s | 0.86s |
Bind Time | 0.54s (± 0.67%) | 0.55s (± 0.62%) | +0.00s (+ 0.55%) | 0.54s | 0.55s |
Check Time | 7.63s (± 0.92%) | 7.58s (± 0.78%) | -0.05s (- 0.68%) | 7.48s | 7.72s |
Emit Time | 2.51s (± 0.78%) | 2.54s (± 0.96%) | +0.03s (+ 1.15%) | 2.48s | 2.61s |
Total Time | 11.51s (± 0.68%) | 11.50s (± 0.72%) | -0.02s (- 0.15%) | 11.37s | 11.74s |
Monaco - node (v12.1.0, x64) | |||||
Memory used | 326,866k (± 0.02%) | 326,850k (± 0.02%) | -16k (- 0.00%) | 326,646k | 326,984k |
Parse Time | 1.56s (± 0.69%) | 1.56s (± 1.00%) | -0.00s (- 0.26%) | 1.53s | 1.59s |
Bind Time | 0.76s (± 1.02%) | 0.76s (± 0.45%) | -0.00s (- 0.53%) | 0.75s | 0.76s |
Check Time | 5.76s (± 0.66%) | 5.78s (± 0.39%) | +0.01s (+ 0.23%) | 5.71s | 5.81s |
Emit Time | 3.28s (± 0.48%) | 3.28s (± 0.52%) | -0.00s (- 0.12%) | 3.24s | 3.31s |
Total Time | 11.37s (± 0.49%) | 11.37s (± 0.41%) | +0.00s (+ 0.03%) | 11.25s | 11.46s |
TFS - node (v12.1.0, x64) | |||||
Memory used | 289,745k (± 0.02%) | 289,675k (± 0.07%) | -70k (- 0.02%) | 288,847k | 289,941k |
Parse Time | 1.31s (± 1.22%) | 1.29s (± 0.74%) | -0.01s (- 0.84%) | 1.28s | 1.32s |
Bind Time | 0.75s (± 1.01%) | 0.76s (± 0.65%) | +0.00s (+ 0.13%) | 0.75s | 0.77s |
Check Time | 5.33s (± 0.62%) | 5.32s (± 0.52%) | -0.01s (- 0.15%) | 5.24s | 5.39s |
Emit Time | 3.50s (± 0.68%) | 3.48s (± 0.76%) | -0.02s (- 0.63%) | 3.43s | 3.54s |
Total Time | 10.88s (± 0.50%) | 10.85s (± 0.36%) | -0.03s (- 0.30%) | 10.77s | 10.95s |
material-ui - node (v12.1.0, x64) | |||||
Memory used | 448,352k (± 0.02%) | 450,817k (± 0.06%) | +2,466k (+ 0.55%) | 449,731k | 451,099k |
Parse Time | 1.85s (± 0.44%) | 1.84s (± 0.56%) | -0.01s (- 0.59%) | 1.82s | 1.87s |
Bind Time | 0.68s (± 0.98%) | 0.68s (± 0.65%) | -0.00s (- 0.15%) | 0.67s | 0.69s |
Check Time | 13.10s (± 0.73%) | 13.10s (± 0.62%) | -0.00s (- 0.03%) | 12.94s | 13.27s |
Emit Time | 0.00s (± 0.00%) | 0.00s (± 0.00%) | 0.00s ( NaN%) | 0.00s | 0.00s |
Total Time | 15.64s (± 0.64%) | 15.62s (± 0.53%) | -0.02s (- 0.10%) | 15.44s | 15.79s |
xstate - node (v12.1.0, x64) | |||||
Memory used | 546,965k (± 1.32%) | 546,968k (± 1.31%) | +3k (+ 0.00%) | 543,492k | 575,977k |
Parse Time | 2.59s (± 0.38%) | 2.58s (± 0.50%) | -0.01s (- 0.50%) | 2.55s | 2.60s |
Bind Time | 1.04s (± 1.11%) | 1.03s (± 1.03%) | -0.00s (- 0.29%) | 1.01s | 1.06s |
Check Time | 1.50s (± 0.83%) | 1.49s (± 0.78%) | -0.00s (- 0.20%) | 1.47s | 1.52s |
Emit Time | 0.07s (± 0.00%) | 0.07s (± 0.00%) | 0.00s ( 0.00%) | 0.07s | 0.07s |
Total Time | 5.20s (± 0.32%) | 5.17s (± 0.51%) | -0.02s (- 0.44%) | 5.11s | 5.22s |
Angular - node (v14.15.1, x64) | |||||
Memory used | 335,338k (± 0.01%) | 335,372k (± 0.01%) | +35k (+ 0.01%) | 335,286k | 335,431k |
Parse Time | 2.08s (± 0.63%) | 2.07s (± 0.69%) | -0.01s (- 0.38%) | 2.04s | 2.11s |
Bind Time | 0.90s (± 0.84%) | 0.91s (± 1.18%) | +0.01s (+ 0.77%) | 0.90s | 0.95s |
Check Time | 5.74s (± 0.37%) | 5.76s (± 0.44%) | +0.02s (+ 0.35%) | 5.67s | 5.79s |
Emit Time | 6.40s (± 0.61%) | 6.42s (± 0.88%) | +0.02s (+ 0.38%) | 6.31s | 6.58s |
Total Time | 15.12s (± 0.32%) | 15.16s (± 0.47%) | +0.04s (+ 0.26%) | 15.02s | 15.35s |
Compiler-Unions - node (v14.15.1, x64) | |||||
Memory used | 192,627k (± 0.02%) | 192,648k (± 0.01%) | +21k (+ 0.01%) | 192,598k | 192,702k |
Parse Time | 0.84s (± 0.87%) | 0.84s (± 0.90%) | +0.01s (+ 0.84%) | 0.83s | 0.87s |
Bind Time | 0.58s (± 0.69%) | 0.58s (± 1.01%) | -0.00s (- 0.69%) | 0.57s | 0.59s |
Check Time | 7.66s (± 0.60%) | 7.68s (± 0.65%) | +0.02s (+ 0.30%) | 7.56s | 7.77s |
Emit Time | 2.50s (± 0.59%) | 2.51s (± 0.43%) | +0.01s (+ 0.44%) | 2.49s | 2.54s |
Total Time | 11.58s (± 0.44%) | 11.61s (± 0.41%) | +0.04s (+ 0.33%) | 11.49s | 11.68s |
Monaco - node (v14.15.1, x64) | |||||
Memory used | 325,577k (± 0.01%) | 325,588k (± 0.01%) | +11k (+ 0.00%) | 325,537k | 325,638k |
Parse Time | 1.57s (± 0.47%) | 1.57s (± 0.60%) | -0.00s (- 0.19%) | 1.56s | 1.60s |
Bind Time | 0.79s (± 0.98%) | 0.79s (± 0.89%) | +0.00s (+ 0.25%) | 0.78s | 0.81s |
Check Time | 5.66s (± 0.41%) | 5.67s (± 0.71%) | +0.01s (+ 0.11%) | 5.61s | 5.76s |
Emit Time | 3.36s (± 0.75%) | 3.35s (± 0.65%) | -0.01s (- 0.36%) | 3.30s | 3.38s |
Total Time | 11.38s (± 0.37%) | 11.38s (± 0.55%) | -0.01s (- 0.05%) | 11.27s | 11.54s |
TFS - node (v14.15.1, x64) | |||||
Memory used | 288,764k (± 0.01%) | 288,771k (± 0.01%) | +8k (+ 0.00%) | 288,720k | 288,851k |
Parse Time | 1.32s (± 1.02%) | 1.32s (± 1.28%) | +0.00s (+ 0.23%) | 1.29s | 1.36s |
Bind Time | 0.76s (± 0.91%) | 0.76s (± 1.41%) | +0.00s (+ 0.53%) | 0.74s | 0.79s |
Check Time | 5.32s (± 0.48%) | 5.32s (± 0.64%) | -0.00s (- 0.02%) | 5.26s | 5.41s |
Emit Time | 3.64s (± 1.91%) | 3.62s (± 1.69%) | -0.01s (- 0.41%) | 3.46s | 3.68s |
Total Time | 11.03s (± 0.72%) | 11.02s (± 0.72%) | -0.00s (- 0.05%) | 10.79s | 11.13s |
material-ui - node (v14.15.1, x64) | |||||
Memory used | 446,630k (± 0.00%) | 449,208k (± 0.00%) | +2,578k (+ 0.58%) | 449,175k | 449,237k |
Parse Time | 1.90s (± 0.50%) | 1.89s (± 0.44%) | -0.02s (- 1.00%) | 1.87s | 1.90s |
Bind Time | 0.73s (± 1.27%) | 0.73s (± 0.88%) | +0.00s (+ 0.55%) | 0.71s | 0.74s |
Check Time | 13.25s (± 0.92%) | 13.26s (± 0.72%) | +0.01s (+ 0.10%) | 13.04s | 13.51s |
Emit Time | 0.00s (± 0.00%) | 0.00s (± 0.00%) | 0.00s ( NaN%) | 0.00s | 0.00s |
Total Time | 15.88s (± 0.80%) | 15.88s (± 0.60%) | -0.00s (- 0.00%) | 15.67s | 16.13s |
xstate - node (v14.15.1, x64) | |||||
Memory used | 541,401k (± 0.00%) | 541,456k (± 0.00%) | +55k (+ 0.01%) | 541,393k | 541,500k |
Parse Time | 2.62s (± 0.52%) | 2.62s (± 0.32%) | -0.00s (- 0.15%) | 2.60s | 2.64s |
Bind Time | 1.18s (± 0.80%) | 1.18s (± 0.92%) | +0.01s (+ 0.42%) | 1.15s | 1.20s |
Check Time | 1.53s (± 0.48%) | 1.54s (± 0.31%) | +0.01s (+ 0.59%) | 1.53s | 1.55s |
Emit Time | 0.07s (± 3.14%) | 0.07s (± 4.66%) | +0.00s (+ 2.82%) | 0.07s | 0.08s |
Total Time | 5.41s (± 0.32%) | 5.41s (± 0.36%) | +0.00s (+ 0.07%) | 5.36s | 5.45s |
Machine Name | ts-ci-ubuntu |
---|---|
Platform | linux 4.4.0-210-generic |
Architecture | x64 |
Available Memory | 16 GB |
Available Memory | 1 GB |
CPUs | 4 × Intel(R) Core(TM) i7-4770 CPU @ 3.40GHz |
- node (v10.16.3, x64)
- node (v12.1.0, x64)
- node (v14.15.1, x64)
- Angular - node (v10.16.3, x64)
- Angular - node (v12.1.0, x64)
- Angular - node (v14.15.1, x64)
- Compiler-Unions - node (v10.16.3, x64)
- Compiler-Unions - node (v12.1.0, x64)
- Compiler-Unions - node (v14.15.1, x64)
- Monaco - node (v10.16.3, x64)
- Monaco - node (v12.1.0, x64)
- Monaco - node (v14.15.1, x64)
- TFS - node (v10.16.3, x64)
- TFS - node (v12.1.0, x64)
- TFS - node (v14.15.1, x64)
- material-ui - node (v10.16.3, x64)
- material-ui - node (v12.1.0, x64)
- material-ui - node (v14.15.1, x64)
- xstate - node (v10.16.3, x64)
- xstate - node (v12.1.0, x64)
- xstate - node (v14.15.1, x64)
Benchmark | Name | Iterations |
---|---|---|
Current | 49552 | 10 |
Baseline | main | 10 |
Developer Information:
This is a feature I've been waiting for a long time, but I forgot why. 😄
Hi, this PR looks fantastic (I've been hoping for this feature for a long time)! Wondering what the status is?
Is there any progress for this feature?
I hope the pending reviews can be done soon so we will see this released soon. This would open the door to a lot of interesting things.
This PR is currently on hold. The main use cases for this feature require a fair amount of complexity that is likely to run any implementation against the recursion depth limiter. Such types are expensive to compute and check, and often result in degraded performance in an editor. It's unlikely that we will ship a feature that introduces this much complexity without first making significant improvements in overall type checking performance.
I do plan to keep this PR alive and will periodically update it, but I do not foresee it shipping in the near future.
There are also use cases which require no recursions.
One example is the generation of GraphQL types from .ts
files as described here:
https://the-guild.dev/graphql/codegen/plugins/presets/gql-tag-operations-preset
The idea is to generate return types for queries based on your written code. For example:
import { gql } from "gql.generated"; // <--- gqls types are generated from all .ts files
const userQuery = const USER_QUERY = gql(`
query User($id: String!) {
user(id: $id) {
id
name
}
}
`);
execute(userQuery, "12") // <--- typed - will return Promise<{user: { id: string, name: string } }>
However for graphql fragments we would need to use template literals to merge the return types of the query and fragments:
import { gql } from "gql.generated";
const fragment = gql`a fragment query`;
const userQuery = gql`a graphql query { ${fragment} }`
Another year has passed, and version 5.x has now been released. This version has optimized the performance of comparison. Is it possible to consider introducing this feature in the new version? This helps us a lot, thank you very much for your work.
i wrote a working type level parser for my library's html template string DSL so it can be typesafe but it's useless without this PR. JSX isn't an option due to lack of ability to cache static parts with default tooling. i'd love to see this merged.
@rbuckton Any updates? Aren't v5's perf enhancements sufficient now?
@typescript-bot pack this
Starting jobs; this comment will be updated as builds start and complete.
Command | Status | Results |
---|---|---|
pack this |
✅ Started |
Hey @rbuckton, I've packed this into an installable tgz. You can install it for testing by referencing it in your package.json
like so:
{
"devDependencies": {
"typescript": "https://typescript.visualstudio.com/cf7ac146-d525-443c-b23c-0d58337efebc/_apis/build/builds/160237/artifacts?artifactName=tgz&fileId=C4F63B683D4A1D20951F7242BAF3E88934805D10EB48C11D866934D3E86690CF02&fileName=/typescript-4.8.0-insiders.20240308.tgz"
}
}
and then running npm install
.
There is also a playground for this build and an npm module you can use via "typescript": "npm:@typescript-deploys/[email protected]"
.;
@rbuckton Any updates? Aren't v5's perf enhancements sufficient now?
No, unfortunately. The performance concerns we have are related to the complex conditional types and inference that are necessary to "parse" a string literal type, and that still isn't very efficient at the moment.
@rbuckton Has ArkType not proven it can be done efficiently at this point?
Even with the overhead of type-level string parsing (including syntactic and semantic validation), types are often 3-10x less expensive than equivalent Zod.
It would be a shame not to ship what would be an awesome feature just because it is possible to use inefficiently.