type S=string;type N=never;type C='"'|'\\'|'/';type Q<A,B extends S>=[A,B];type D<T>={[P in keyof T]:T[P]};type B={b:'\b',t:'\t',n:'\n',r:'\r',f:'\f'};type W<T extends S>=T extends`${' '|'\n'|'\t'|'\r'}${infer T}`?W<T>:T;type X<_ extends S,T extends S=W<_>>= T extends`${boolean|null}${infer R}`?T extends`${infer T extends boolean|null}${R}`?[T,R]:N:N;type T<I extends S,O extends S=''>=I extends`${infer K}${infer R}`?K extends B[keyof B]?N:K extends '\\'?R extends`${infer K extends C|keyof B}${infer R}`?K extends keyof B?T<R,`${O}${B[K]}`>:T<R,`${O}${K}`>:N:K extends'"'?[O,R]:T<R,`${O}${K}`>:N;type L<_ extends S,O={},R extends S=W<_>>=R extends`"${infer R}`?T<R> extends Q<infer K extends S,infer R>?W<R>extends`:${infer R}`?M<R> extends Q<infer V,infer R>?W<R>extends`${infer E extends','|'}'}${infer R}`?E extends'}'?[D<O&Record<K,V>>,R]:L<R,D<O&Record<K, V>>>:N:N:N:N:R extends`}${infer R}`?[{},R]:N;type K<_ extends S,O extends unknown[]=[],R extends S=W<_>>=R extends`]${infer R}`?[[],R]:M<R>extends Q<infer V,infer R>?W<R>extends`${infer E extends','|']'}${infer R}`?E extends']'?[[...O,V],R]:K<R,[...O,V]>:N:N;type M<_ extends S,I extends S=W<_>>=I extends`${infer F}${infer R}`?F extends'"'?T<R>:F extends'{'?L<R>:F extends'['?K<R>:X<I>:N;type Parse<T extends S>=M<T>extends[infer T,infer R extends S]?W<R>extends''?T:N:N;
Solution by tomoriny #35142
type Parse<T extends string>
= T extends `${Space}${infer U}` ? Parse<U>
: T extends `${infer U}${Space}` ? Parse<U>
: T extends `${infer U extends boolean | null}` ? U
: T extends `"${infer U}` ? ParseString<U>
: T extends `[${infer U}` ? ParseSequence<U, ']'>
: T extends `{${infer U}` ? ParseSequence<U, '}'> : never
type VaildString<T extends string, V = T> =
T extends `${string}${Escapes[keyof Omit<Escapes, '/'>]}${string}` ? never : V
type ParseString<T extends string> = T extends `${infer L}\\${infer E}${infer R}`
? VaildString<L, E extends keyof Escapes ? `${L}${Escapes[E]}${ParseString<R>}` : never>
: T extends `${infer U}"` ? VaildString<U> : never
type ParseSequence<T extends string, End extends ']' | '}', Last extends string = ''>
= `${Last}${T}` extends End ? End extends ']' ? [] : {}
: T extends `${infer First},${infer Rest}`
? (End extends ']' ? Parse<`${Last}${First}`> : ParseEntry<`${Last}${First}`>) extends never
? ParseSequence<Rest, End, `${Last}${First},`> : ParseSequence<Rest, End> extends never ? never
: End extends ']' ? [Parse<`${Last}${First}`>, ...ParseSequence<Rest, End>]
: Prettify<ParseEntry<`${Last}${First}`> & ParseSequence<Rest, End>>
: `${Last}${T}` extends `${infer U}${End}`
? End extends ']' ? Parse<U> extends never ? never : [Parse<U>]
: {} extends ParseEntry<U> ? never : Prettify<ParseEntry<U>> : never
type ParseEntry<T extends string> =
T extends `${infer Key}:${infer Value}`
? Parse<Key> extends keyof any ? Parse<Value> extends never ? never
: Record<Parse<Key>, Parse<Value>> : never : never
type Prettify<T> = { [K in keyof T]: T[K] } & {}
type Space = ' ' | '\t' | '\n' | '\r'
type Escapes = { '"': '"'; '\\': '\\'; '/': '/'; 'b': '\b'; 'f': '\f'; 'n': '\n'; 'r': '\r'; 't': '\t' }
Solution by montmorill #35125
Spaces and escaping quotes are not supported
// examples
type example1 = Parse<'"text"'> // string
type example2 = Parse<'123.322'> // number
type example3 = Parse<'null'> // null
type example4 = Parse<'true'> // boolean
type example5 = Parse<'false'> // boolean
type example6 = Parse<`{
"x":"y",
"foo":{
"bar":"baz",
"arr":[123.123,true,{"test":10}],
"nested":{"nested":{"nested":true}}
}
}`> /*
{
x: string;
foo: {
bar: string;
arr: [number, boolean, {
test: number;
}];
nested: {
nested: {
nested: boolean;
};
};
};
}
*/
type example7 = Parse<`[
true,
false,
null,
123.123,
[123,{},{"foo":"bar","baz":{"foo":1}}],
{"nested":{"nested":[]}}
]`> /*
[boolean, boolean, null, number, [number, {}, {
foo: string;
baz: {
foo: number;
};
}], {
nested: {
nested: [];
};
}]
*/
type Parse<T extends string, JSON extends string = RemoveNewLines<T>> = (
| ParseNumber<JSON>
| ParseNumber<JSON>
| ParseString<JSON>
| ParseBoolean<JSON>
| ParseArray<JSON>
| ParseObj<JSON>
| ParseNull<JSON>
) extends [infer Parsed, any]
? ExpandRecursively<Parsed>
: never
type ParseString<JSON extends string> = JSON extends `"${infer Str}"${string}`
? [string, `\"${Str}\"`]
: never
type ParseStringEnum<JSON extends string> = JSON extends `"${infer Str}"${string}`
? [Str, `\"${Str}\"`]
: never
type ParseNull<JSON extends string> = JSON extends `null${string}`
? [null, 'null']
: never
type ParseNumber<JSON extends string, End extends string = never> = [End] extends [never]
? JSON extends `${infer Num extends number}`
? [number, `${Num}`]
: never
: JSON extends `${infer Num extends number}${End}${string}`
? [number, `${Num}`]
: never
type ParseBoolean<JSON extends string> = JSON extends `true${string}`
? [boolean, 'true']
: JSON extends `false${string}`
? [boolean, 'false']
: never
type ParseArray<
JSON extends string,
StringResult extends string = '[',
Result extends any[] = []
> = JSON extends `[${infer RestArray}`
? RestArray extends `]${string}`
? [Result,`${StringResult}]`]
: ParseNull<RestArray> | ParseNumber<RestArray, ','> | ParseNumber<RestArray, ']'> | ParseString<RestArray> | ParseBoolean<RestArray> | ParseArray<RestArray> | ParseObj<RestArray> extends infer FirstElem extends [any, string]
? RestArray extends `${FirstElem[1]}${infer RestElements}`
? ParseArray<
`[${RemoveHeadComma<RestElements>}`,
`${StringResult extends '[' ? '[' : `${StringResult},`}${FirstElem[1]}`,
[...Result, FirstElem[0]]
>
: never
: never
: never
type ParseObj<
JSON extends string,
StringResult extends string = '{',
Result extends Record<string, any> = {}
> = JSON extends `{${infer ObjFields}`
? ObjFields extends `}${string}`
? [Result, `${StringResult}}`]
: ParseStringEnum<ObjFields> extends infer ObjKey extends [any, string]
? ObjFields extends `${ObjKey[1]}:${infer RestFields}`
? ParseNull<RestFields> | ParseNumber<RestFields, ','> | ParseNumber<RestFields, '}'> | ParseString<RestFields> | ParseBoolean<RestFields> | ParseArray<RestFields> | ParseObj<RestFields> extends infer ObjValue extends [any, string]
? RestFields extends `${ObjValue[1]}${infer RestObject}`
? ParseObj<
`{${RemoveHeadComma<RestObject>}`,
`${StringResult extends '{' ? '{' : `${StringResult},`}${ObjKey[1]}:${ObjValue[1]}`,
Result & Record<ObjKey[0], ObjValue[0]>
>
: never
: never
: never
: never
: never;
type RemoveHeadComma<Str extends string> = Str extends `,${infer Result}` ? Result : Str;
type RemoveNewLines<Str extends string, Result extends string = ''> = Str extends `${infer Before}\n${infer After}`
? `${Result}${Before}${RemoveNewLines<After>}`
: `${Result}${Str}`
type ExpandRecursively<T> = T extends (...args: infer A) => infer R
? (...args: ExpandRecursively<A>) => ExpandRecursively<R>
: T extends object
? T extends infer O
? { [K in keyof O]: ExpandRecursively<O[K]> }
: never
: T
Solution by AlexeyDuybo #34163
type Pure<T> = {
[P in keyof T]: T[P] extends object ? Pure<T[P]> : T[P];
};
type SetProperty<T, K extends PropertyKey, V> = {
[P in keyof T | K]: P extends K ? V : P extends keyof T ? T[P] : never;
};
type StaticToken = "{" | "}" | ":" | "," | "[" | "]";
type Token = StaticToken | "true" | "false" | "null" | { string: string };
type StaticValues = { true: true; false: false; null: null };
type SkipWhitespace<S extends string> = S extends `${
| " "
| "\n"
| "\r"
| "\t"}${infer Rest}`
? SkipWhitespace<Rest>
: S;
type Escapes = {
n: "\n";
r: "\r";
b: "\b";
f: "\f";
};
type Unescape<S extends string> =
S extends `${infer Prefix}\\${infer E extends keyof Escapes}${infer Suffix}`
? `${Prefix}${Escapes[E]}${Unescape<Suffix>}`
: S;
type CollectString<
S extends string,
T extends Token[]
> = S extends `${infer Literal}"${infer Rest}`
? Tokenize<Rest, [...T, { string: Unescape<Literal> }]>
: never;
type ParseObject<R, T extends Token[]> = T extends [
"}",
...infer AfterDirectCloseRest
]
? [R, AfterDirectCloseRest]
: T extends [
infer P extends { string: string },
":",
...infer ObjectValueRest extends Token[]
]
? ParseResult<{}, ObjectValueRest> extends [
infer V,
infer AfterValueRest extends [] | Token[]
]
? AfterValueRest extends [",", ...infer ObjectRest extends Token[]]
? ParseObject<SetProperty<R, P["string"], V>, ObjectRest>
: AfterValueRest extends ["}", ...infer AfterObjectRest]
? [SetProperty<R, P["string"], V>, AfterObjectRest]
: never
: never
: never;
type ParseArray<R extends any[], T extends Token[]> = T extends [
"]",
...infer AfterDirectCloseRest
]
? [R, AfterDirectCloseRest]
: ParseResult<any, T> extends [infer V, infer ArrayRest]
? ArrayRest extends [",", ...infer ArrayRestCntd extends Token[]]
? ParseArray<[...R, V], ArrayRestCntd>
: ArrayRest extends ["]", ...infer AfterArrayRest]
? [[...R, V], AfterArrayRest]
: never
: never;
type ParseResult<T, K extends Token[]> = K extends []
? [T, []]
: K extends [
infer CurrentToken extends Token,
...infer RestTokens extends Token[]
]
? CurrentToken extends keyof StaticValues
? [StaticValues[CurrentToken], RestTokens]
: CurrentToken extends { string: infer S }
? [S, RestTokens]
: CurrentToken extends "["
? ParseArray<[], RestTokens>
: CurrentToken extends "{"
? ParseObject<{}, RestTokens>
: never
: never;
type Tokenize<
T extends string,
S extends Token[] = []
> = SkipWhitespace<T> extends ""
? S
: SkipWhitespace<T> extends `true${infer Rest}`
? Tokenize<Rest, [...S, "true"]>
: SkipWhitespace<T> extends `false${infer Rest}`
? Tokenize<Rest, [...S, "false"]>
: SkipWhitespace<T> extends `null${infer Rest}`
? Tokenize<Rest, [...S, "null"]>
: SkipWhitespace<T> extends `${infer Static extends StaticToken}${infer Rest}`
? Tokenize<Rest, [...S, Static]>
: SkipWhitespace<T> extends `"${infer Rest}`
? CollectString<Rest, S>
: never;
type ParseLiteral<T extends Token[]> = ParseResult<{}, T>;
type Parse<T extends string> = Pure<ParseLiteral<Tokenize<T>>[0]>;
Solution by dexmo007 #28742
// ===============================================
// test file and complex test data parse example, see: https://github.com/Max10240/tiny-json5-parser/blob/main/packages/ts-type-json-parser/src/index.ts
// ===============================================
type TTokenType =
'L_BRACE'
| 'R_BRACE'
| 'L_S_BRACE'
| 'R_S_BRACE'
| 'COMMA'
| 'COLON'
| 'TRUE'
| 'FALSE'
| 'NULL'
| 'NUMBER'
| 'STRING'
| 'EOF';
type SimpleTokenMap = {
'{': 'L_BRACE';
'}': 'R_BRACE';
'[': 'L_S_BRACE';
']': 'R_S_BRACE';
',': 'COMMA';
':': 'COLON';
'true': 'TRUE';
'false': 'FALSE';
'null': 'NULL';
};
interface IToken {
type: TTokenType;
value: string;
}
type IsExtends<T, U> = T extends U ? true : false;
type Cast<T, To> = T extends To ? T : never;
type ReMap<T> = {[P in keyof T]: ReMap<T[P]>};
type StringToNumber<T extends string> = T extends `${infer N extends number}` ? N : never;
type SliceFrom<T extends unknown[], Start extends number = 0, Filtered extends unknown[] = []> = Filtered['length'] extends Start
? T
: T extends [infer H, ...infer Rest]
? SliceFrom<Rest, Start, [...Filtered, H]>
: [];
type SliceStrFrom<T extends string, Start extends number = 0, Counter extends 0[] = []> = Counter['length'] extends Start
? T
: T extends `${infer H}${infer Rest}`
? SliceStrFrom<Rest, Start, [...Counter, 0]>
: '';
type StartsWith<Start extends string, S extends string> = S extends `${Start}${infer R}` ? true : boolean;
type JsonNumber<T extends string> = number & { value: T };
type Match<Pattern extends string, S extends string> = S extends `${infer P extends Pattern}${infer R}` ? [true, P, R] : [false, '', S];
type MatchSequence<Pattern extends string, S extends string> = S extends `${Pattern}${infer R}` ? [true, Pattern, R] : [false, '', S];
type MatchPureNumber<S extends string, Result extends string = ''> = S extends `${infer H extends number}${infer R}`
? MatchPureNumber<R, `${Result}${H}`>
: Result extends ''
? [false, '', `${Result}${S}`]
: [true, Result, S];
type MatchFloatNum<S extends string, Result extends string = ''> = MatchPureNumber<S> extends infer IntR extends [boolean, string, string]
? IntR[0] extends true
? Match<'.', IntR[2]>[0] extends true
? MatchPureNumber<SliceStrFrom<IntR[2], 1>> extends infer DecimalR extends [boolean, string, string]
? DecimalR[0] extends true
? [true, `${IntR[1]}.${DecimalR[1]}`, DecimalR[2]]
: [false, '', S, `expected number behind '.' at ${SliceStrFrom<IntR[2], 1>}`]
: never
: [true, IntR[1], IntR[2]]
: [false, '', S, `expected number at ${S}`]
: never;
type MatchNumber<S extends string> = MatchFloatNum<S> extends infer FloatR extends [boolean, string, string, string?]
? FloatR[0] extends true
? Match<'e', FloatR[2]>[0] extends true
? Match<'+' | '-', SliceStrFrom<FloatR[2], 1>> extends infer ExpoSignR extends [boolean, string, string]
? MatchPureNumber<ExpoSignR[2]> extends infer ExpoR extends [boolean, string, string]
? ExpoR[0] extends true
? [true, `${FloatR[1]}e${ExpoSignR[1]}${ExpoR[1]}`, ExpoR[2]]
: [false, '', S, `expected expo behind 'e' at ${ExpoSignR[2]}`]
: never
: never
: [true, FloatR[1], FloatR[2]]
: [false, '', S, `expected number at ${S}`]
: never;
type EscapeCharMap = {
'"': '"';
'\\': '\\';
'/': '/';
'b': '\b';
'f': '\f';
'n': '\n';
'r': '\r';
't': '\t';
};
type MatchStringContent<S extends string, Result extends string = ''> = Match<'"', S>[0] extends true
? [true, Result, S]
: Match<'\r' | '\n', S>[0] extends true
? [false, '', `${Result}${S}`, `unexpected token after ${Result}`]
: Match<'\\', S>[0] extends true
? Match<string, Match<'\\', S>[2]> extends infer EscapeCharR extends [boolean, string, string]
? [EscapeCharR[0], IsExtends<EscapeCharR[1], keyof EscapeCharMap>][number] extends true
? MatchStringContent<EscapeCharR[2], `${Result}${EscapeCharMap[EscapeCharR[1] & keyof EscapeCharMap]}`>
: [false, '', `${Result}${S}`, `unexpected escape char after ${Result}`]
: never
: Match<string, S>[0] extends true
? MatchStringContent<Match<string, S>[2], `${Result}${Match<string, S>[1]}`>
: [false, '', `${Result}${S}`, `unexpected EOF after ${Result}`];
type MatchString<S extends string> = Match<'"', S>[0] extends true
? MatchStringContent<Match<'"', S>[2]> extends infer MatchStringContentResult extends [boolean, string, string, string?]
? MatchStringContentResult[0] extends true
? [true, MatchStringContentResult[1], Match<string, MatchStringContentResult[2]>[2]]
: [false, '', S, MatchStringContentResult[3]]
: 1
: [false, '', S, `expect '"' at start`];
type MatchSimpleToken<S extends string, MatchOptions extends keyof SimpleTokenMap = keyof SimpleTokenMap> = (MatchOptions extends unknown
? MatchSequence<MatchOptions, S> extends infer MatchResult extends [boolean, string, string, string?]
? MatchResult[0] extends true
? [true, { type: SimpleTokenMap[MatchOptions], value: MatchOptions }, MatchResult[2]]
: never
: never
: never) extends infer R
? [R] extends [never]
? [false, never, S]
: R
: never;
type Lexer<S extends string, R extends IToken[] = []> = S extends ''
? [true, R]
: Match<' ' | '\t' | '\r' | '\n', S> extends infer MatchWSResult extends [boolean, string, string]
? MatchWSResult[0] extends true
? Lexer<MatchWSResult[2], R>
: MatchSimpleToken<S> extends infer MatchSTResult extends [boolean, IToken, string]
? MatchSTResult[0] extends true
? Lexer<MatchSTResult[2], [...R, MatchSTResult[1]]>
: MatchNumber<S> extends infer MatchNumResult extends [boolean, string, string, string?]
? MatchNumResult[0] extends true
? Lexer<MatchNumResult[2], [...R, { type: 'NUMBER', value: MatchNumResult[1] }]>
: MatchString<S> extends infer MatchStrResult extends [boolean, string, string, string?]
? MatchStrResult[0] extends true
? Lexer<MatchStrResult[2], [...R, { type: 'STRING', value: MatchStrResult[1] }]>
: [false, R, `unexpected token at '${S}'`]
: never
: never
: never
: never;
type MatchToken<Types extends TTokenType[], T extends IToken[]> = Types extends [infer H extends TTokenType, ...infer Rest extends TTokenType[]]
? T extends [infer HT extends IToken, ...infer RestT extends IToken[]]
? HT['type'] extends H
? MatchToken<Rest, RestT>
: [false]
: [false]
: [true, T];
type MatchAnyToken<Type extends TTokenType, T extends IToken[]> = (Type extends unknown
? MatchToken<[Type], T>[0] extends true
? [true, T[0], MatchToken<[Type], T>[1]]
: never
: 2) extends infer Result
? [Result] extends [never]
? [false, T]
: Result
: never;
type MatchKVPair<T extends IToken[], Result extends Record<string, unknown> = {}> =
MatchToken<['STRING', 'COLON'], T> extends infer KeyColonResult extends ([true, IToken[]] | [false])
? KeyColonResult[0] extends true
? Parser<SliceFrom<T, 2>> extends infer ValueResult extends [boolean, unknown, IToken[], string?]
? ValueResult[0] extends true
? MatchToken<['COMMA'], ValueResult[2]>[0] extends true
? MatchKVPair<SliceFrom<ValueResult[2], 1>, Result & { [P in T[0]['value']]: ValueResult[1] }>
: [true, Result & { [P in T[0]['value']]: ValueResult[1] }, ValueResult[2]]
: [false, Result, [], `error while parsing value of KV pair, current: ${T[0]['value']}:`]
: never
: [false, Result, [], `error while parsing key of KV pair, current: ${T[0]['value']}:`]
: never;
type ParseObject<T extends IToken[]> = MatchToken<['L_BRACE'], T>[0] extends true
? MatchToken<['L_BRACE', 'R_BRACE'], T>[0] extends true
? [true, {}, SliceFrom<T, 2>]
: MatchKVPair<SliceFrom<T, 1>> extends infer KVPairResult extends [boolean, unknown, IToken[], string?]
? KVPairResult[0] extends true
? MatchToken<['R_BRACE'], KVPairResult[2]>[0] extends true
? [true, KVPairResult[1], SliceFrom<KVPairResult[2], 1>]
: [false, `expected '}' at ${KVPairResult[2][0]['value']}`]
: [false, T]
: never
: [false, `expected '{' at ${T[0]['value']}`];
type ParseArrayElems<T extends IToken[], Result extends unknown[] = []> =
Parser<T> extends infer ElemR extends [boolean, unknown, IToken[], string?]
? ElemR[0] extends true
? MatchToken<['COMMA'], ElemR[2]>[0] extends true
? ParseArrayElems<SliceFrom<ElemR[2], 1>, [...Result, ElemR[1]]>
: [true, [...Result, ElemR[1]], ElemR[2]]
: [false, Result, [], `error while parsing array elem, current: ${T[0]['value']}:`]
: never;
type ParseArray<T extends IToken[]> = MatchToken<['L_S_BRACE'], T>[0] extends true
? MatchToken<['L_S_BRACE', 'R_S_BRACE'], T>[0] extends true
? [true, [], SliceFrom<T, 2>]
: ParseArrayElems<SliceFrom<T, 1>> extends infer ArrElemsR extends [boolean, unknown[], IToken[], string?]
? ArrElemsR[0] extends true
? MatchToken<['R_S_BRACE'], ArrElemsR[2]>[0] extends true
? [true, ArrElemsR[1], SliceFrom<ArrElemsR[2], 1>]
: [false, never, T, `expected ']' behind elems`]
: [false, never, T, ArrElemsR[3]]
: never
: [false, never, T, `expected '[' at start`];
type SimpleLiteralValueMap = {
TRUE: true;
FALSE: false;
NULL: null;
};
type GetSimpleLiteralValue<T extends IToken> = T['type'] extends 'STRING'
? T['value']
: T['type'] extends 'NUMBER'
? number extends StringToNumber<T['value']>
? JsonNumber<T['value']>
: StringToNumber<T['value']>
: SimpleLiteralValueMap[Cast<T['type'], keyof SimpleLiteralValueMap>];
type Parser<T extends IToken[]> =
MatchAnyToken<'STRING' | 'NUMBER' | 'NULL' | 'TRUE' | 'FALSE', T> extends infer SimpleLiteralResult extends unknown[]
? SimpleLiteralResult[0] extends true
? [true, GetSimpleLiteralValue<T[0]>, SimpleLiteralResult[2]]
: ParseObject<T> extends infer ObjectResult extends unknown[]
? ObjectResult[0] extends true
? [true, ObjectResult[1], ObjectResult[2]]
: ParseArray<T> extends infer ArrayResult extends unknown[]
? ArrayResult[0] extends true
? [true, ArrayResult[1], ArrayResult[2]]
: [false, never, T, `unexpected token: ${T[0]['value']}`]
: never
: never
: never;
type Parse<T extends string> = ReMap<Parser<Lexer<T>[1]>[1]>;
/* _____________ Test Cases _____________ */
import type { Equal, Expect } from '@type-challenges/utils'
type cases = [
Expect<Equal<(
Parse<`
{
"a": "b",
"b": false,
"c": [true, false, "hello", {
"a": "b",
"b": false
}],
"nil": null
}
`>
), (
{
nil: null
c: [true, false, 'hello', {
a: 'b'
b: false
}]
b: false
a: 'b'
}
)>>,
Expect<Equal<Parse<'{}'>, {}>>,
Expect<Equal<Parse<'[]'>, []>>,
Expect<Equal<Parse<'[1]'>, [1]>>,
Expect<Equal<Parse<'true'>, true>>,
Expect<Equal<
Parse<'["Hello", true, false, null]'>,
['Hello', true, false, null]
>>,
Expect<Equal<
(
Parse<`
{
"hello\\r\\n\\b\\f": "world"
}`>
), (
{
'hello\r\n\b\f': 'world'
}
)
>>,
Expect<Equal<Parse<'{ 1: "world" }'>, never>>,
Expect<Equal<Parse<`{ "hello
world": 123 }`>, never>>,
]
/* _____________ Further Steps _____________ */
/*
> Share your solutions: https://tsch.js.org/6228/answer
> View solutions: https://tsch.js.org/6228/solutions
> More Challenges: https://tsch.js.org
*/
Solution by Max10240 #27235
type SpecialChar = {r: '\r', n: '\n', b: '\b', f: '\f'}
type Format<S extends string, Res extends string = ""> =
S extends `\\${infer L extends keyof SpecialChar}${infer R}`
? Format<R, `${Res}${SpecialChar[L]}`>
: S extends `${infer L}${infer R}`
? Format<R, `${Res}${
L extends '}' | ']'
? `,${L}`
: L extends ' ' | '\n' | '\t' ? '' : L
}`>
: Res
type Eval<V> =
V extends `"${infer T}"`
? T
: V extends `${infer B extends boolean | null}`
? B
: V extends `${number}` ? never : V
type ParseObject<S extends string, Res extends object = {}> =
S extends `${'}' | ',}'}${infer R}`
? [Omit<Res, never>, R extends `,${infer P}` ? P : R]
: S extends `${infer K}:${infer R}`
? [Eval<K>] extends [never | boolean | null]
? never
: ParseValue<R> extends [infer V, infer T extends string]
? ParseObject<T, Res & Record<Eval<K>, V>>
: never
: never
type ParseArray<S extends string, Res extends any[] = []> =
S extends `${']' | ',]'}${infer R}`
? [Res, R extends `,${infer P}` ? P : R]
: ParseValue<S> extends [infer V, infer T extends string]
? ParseArray<T, [...Res, V]>
: never
type ParseValue<S extends string> =
S extends `{${infer O}`
? ParseObject<O>
: S extends `[${infer A}`
? ParseArray<A>
: S extends `${infer L},${infer R}`
? [Eval<L>] extends [never] ? [] : [Eval<L>, R]
: [Eval<S>, ""]
type Parse<T extends string> = ParseValue<Format<T>>[0]
Solution by omittee #27130
// Helper =================================
type IgnoreChar = ' ' | '\n' | '\r' | '\b' | '\f'
type ExtractPattern<
T extends string,
_LeftChar extends string = '[',
_RightChar extends string = ']',
_LeftCharCounters extends 0[] = [],
_RightCharCounters extends 0[] = [],
_Result extends string = '',
> = T extends `${ infer F }${ infer Rest }`
? F extends _LeftChar
? ExtractPattern<Rest, _LeftChar, _RightChar, [ ..._LeftCharCounters, 0 ], _RightCharCounters, `${ _Result }${ F }`>
: F extends _RightChar
? ExtractPattern<Rest, _LeftChar, _RightChar, _LeftCharCounters, [ ..._RightCharCounters, 0 ], `${ _Result }${ F }`>
: _LeftCharCounters['length'] extends _RightCharCounters['length']
? _Result
: ExtractPattern<Rest, _LeftChar, _RightChar, _LeftCharCounters, _RightCharCounters, `${ _Result }${ F }`>
: _Result
type TrimBothEnds<T extends string, Chars extends string = IgnoreChar> =
T extends `${ Chars }${ infer Rest }`
? TrimBothEnds<Rest, Chars>
: T extends `${ infer Rest }${ Chars }`
? TrimBothEnds<Rest, Chars>
: T
type ResolveSpecialChar<T extends string, _Map extends Record<'r' | 'n' | 'b' | 'f', string> = { n: '\n', r: '\r', b: '\b', f: '\f', }> =
T extends `${ infer A }\\${ infer I extends 'r' | 'n' | 'b' | 'f' }${ infer B }`
? ResolveSpecialChar<`${ A }${ _Map[I] }${ B }`> : T
// Helper =================================
// ParseObject ============================
type ParseObject<T extends string, _Key extends string = '', _Result extends Record<PropertyKey, unknown> = {}> =
T extends `${ infer F }${ infer Rest }`
? F extends IgnoreChar | ','
? ParseObject<Rest, _Key, _Result>
: F extends '"'
? _Key extends ''
? Rest extends `${ infer Key }":${ infer Rest2 }`
? ParseObject<Rest2, ResolveSpecialChar<Key>, _Result> // extract key
: never
: Rest extends `${ infer StringValue }"${ infer Rest2 }`
? ParseObject<Rest2, '', _Result & Record<_Key, StringValue>> // extract string value
: Rest
: T extends `false${ infer Rest2 }`
? ParseObject<Rest2, '', _Result & Record<_Key, false>>
: T extends `true${ infer Rest2 }`
? ParseObject<Rest2, '', _Result & Record<_Key, true>>
: T extends `null${ infer Rest2 }`
? ParseObject<Rest2, '', _Result & Record<_Key, null>>
: F extends '['
? ExtractPattern<T> extends infer I
? T extends `${ I & string }${ infer Rest2 }`
? ParseObject<Rest2, '', _Result & Record<_Key, Parse<I & string>>>
: never
: never
: F extends '{'
? ExtractPattern<T, '{', '}'> extends infer I
? T extends `${ I & string }${ infer Rest2 }`
? ParseObject<Rest2, '', _Result & Record<_Key, Parse<I & string>>>
: never
: never
: F extends `${ number }`
? never
: _Result
: { [K in keyof _Result]: _Result[K] }
// ParseObject ============================
// ParseArray =============================
type ParseArray<T extends string, _Result extends unknown[] = []> =
T extends `${ infer F }${ infer Rest }`
? F extends IgnoreChar | ','
? ParseArray<Rest, _Result>
: F extends '['
? ExtractPattern<T> extends infer I
? T extends `${ I & string }${ infer Rest2 }`
? ParseArray<Rest2, [ ..._Result, Parse<I & string> ]>
: never
: never
: F extends '{'
? ExtractPattern<T, '{', '}'> extends infer I
? T extends `${ I & string }${ infer Rest2 }`
? ParseArray<Rest2, [ ..._Result, Parse<I & string> ]>
: never
: never
: F extends '"'
? Rest extends `${ infer StringValue }"${ infer Rest2 }`
? ParseArray<Rest2, [ ..._Result, StringValue]>
: never
: T extends `false${ infer Rest2 }`
? ParseArray<Rest2, [ ..._Result, false]>
: T extends `true${ infer Rest2 }`
? ParseArray<Rest2, [ ..._Result, true]>
: T extends `null${ infer Rest2 }`
? ParseArray<Rest2, [ ..._Result, null]>
: F extends `${ number }`
? never
: _Result
: _Result
// ParseArray =============================
type Parse<T extends string, _T extends string = TrimBothEnds<T>> =
_T extends `{${ infer I }}`
? ParseObject<I>
: _T extends `[${ infer I }]`
? ParseArray<I>
: T extends `${ infer I extends boolean }`
? I
: T
Solution by lvjiaxuan #23284
type Escape = {
'"': '"',
'\\': '\\',
'/': '/',
'b': '\b',
'f': '\f',
'n': '\n',
'r': '\r',
't': '\t'
}
type Space = ' ' | '\r' | '\t' | '\n'
type Symbols = '{' | '}' | '[' | ']' | ':' | ','
type SymbolToken<T extends Symbols> = [0, T]
type StringToken<T extends string> = [1, T]
type BooleanToken<T extends boolean> = [2, T]
type NullToken = [3, null]
type Token =
| SymbolToken<Symbols>
| StringToken<string>
| BooleanToken<boolean>
| NullToken
| [number, unknown]
type EvalResult<Output, Tokens extends Token[]> = [Output, Tokens]
type TokenSplit<First extends Token, Rest extends Token[]> = [First, ...Rest]
type Tokenize<Input extends string, Output extends Token[] = []> =
Input extends `${infer First}${infer Rest}`
? First extends Space
? Tokenize<Rest, Output>
: First extends Symbols
? Tokenize<Rest, [...Output, SymbolToken<First>]>
: First extends '"'
? [TakeString<Rest>] extends [never]
? never
: [...Output, ...TakeString<Rest>]
: Input extends `true${infer Rest}`
? Tokenize<Rest, [...Output, BooleanToken<true>]>
: Input extends `false${infer Rest}`
? Tokenize<Rest, [...Output, BooleanToken<false>]>
: Input extends `null${infer Rest}`
? Tokenize<Rest, [...Output, NullToken]>
: never
: Input extends ''
? Output
: never
type TakeString<Input extends string, Output extends string = ''> =
Input extends `\\${infer Rest}`
? Rest extends `${infer First extends keyof Escape}${infer Rest}`
? TakeString<Rest, `${Output}${Escape[First]}`>
: never
: Input extends `${infer First}${infer Rest}`
? First extends '\n'
? never
: First extends '"'
? [StringToken<Output>, ...Tokenize<Rest>]
: TakeString<Rest, `${Output}${First}`>
: never
type EvalPrimitive<Input extends Token[]> =
Input extends TokenSplit<[1 | 2 | 3, infer Output], infer Rest>
? EvalResult<Output, Rest>
: never
type EvalArrayElements<Input extends Token[], Output extends unknown[] = []> =
Input extends TokenSplit<infer First, infer Rest>
? First extends SymbolToken<']'>
? EvalResult<Output, Rest>
: Eval<Input> extends EvalResult<infer Element, infer Rest>
? Rest extends TokenSplit<infer First, infer Rest>
? First extends SymbolToken<']'>
? EvalResult<[...Output, Element], Rest>
: First extends SymbolToken<','>
? EvalArrayElements<Rest, [...Output, Element]>
: never
: never
: never
: never
type EvalArray<Input extends Token[]> =
Input extends TokenSplit<SymbolToken<'['>, infer Rest>
? EvalArrayElements<Rest>
: never
type EvalObjectEntries<Input extends Token[], Output extends Record<string, unknown> = {}> =
Input extends TokenSplit<infer First, infer Rest>
? First extends SymbolToken<'}'>
? EvalResult<Output, Rest>
: Eval<Input> extends EvalResult<infer Key extends string, infer Rest>
? Rest extends TokenSplit<SymbolToken<':'>, infer Rest>
? Eval<Rest> extends EvalResult<infer Value, infer Rest>
? Output & Record<Key, Value> extends infer Output extends Record<string, unknown>
? Rest extends TokenSplit<infer First, infer Rest>
? First extends SymbolToken<'}'>
? EvalResult<Output, Rest>
: First extends SymbolToken<','>
? EvalObjectEntries<Rest, Output>
: never
: never
: never
: never
: never
: never
: never
type EvalObject<Input extends Token[]> =
Input extends TokenSplit<SymbolToken<'{'>, infer Rest>
? EvalObjectEntries<Rest>
: never
type Eval<Input extends Token[]> =
| EvalPrimitive<Input>
| EvalArray<Input>
| EvalObject<Input>
type Merge<T> =
T extends object
? { [P in keyof T]: Merge<T[P]> }
: T
export type Parse<T extends string> =
string extends T
? never
: [Tokenize<T>] extends [never]
? never
: Eval<Tokenize<T>> extends EvalResult<infer Output, []>
? Merge<Output>
: never
Solution by hydrati #22390
type Escape = {
'"': '"',
'\\': '\\',
'/': '/',
'b': '\b',
'f': '\f',
'n': '\n',
'r': '\r',
't': '\t',
}
type Space = ' ' | '\t' | '\0' | '\n'
type Symbol = '{' | '}' | '[' | ']' | ',' | ':'
type SymbolToken<T extends Symbol> = ['symbol', T]
type StringToken<T extends string> = ['string', T]
type BooleanToken<T extends boolean> = ['boolean', T]
type NullToken = ['null']
type Token =
| SymbolToken<Symbol>
| StringToken<string>
| BooleanToken<boolean>
| NullToken
type EvalResult<T, R extends Token[]> = [T, R]
type TokenFirst<T extends Token, R extends Token[]> = [T, ...R]
type SpreadObject<T> = T extends object ? {
[P in keyof T] : SpreadObject<T[P]>
} : T
type MergeRecord<T extends Record<string, unknown>, K extends string, V> =
SpreadObject<T & Record<K, V>>
type Tokenize<T extends string, O extends Token[] = []> =
T extends `${infer P}${infer R}`
? P extends Space
? Tokenize<R, O>
: P extends Symbol
? Tokenize<R, [...O, SymbolToken<P>]>
: P extends '"'
? [...O, ...TakeString<R>]
: T extends `true${infer R}`
? Tokenize<R, [...O, BooleanToken<true>]>
: T extends `false${infer R}`
? Tokenize<R, [...O, BooleanToken<false>]>
: T extends `null${infer R}`
? Tokenize<R, [...O, NullToken]>
: never
: O
type TakeString<T extends string, O extends string = ''> =
T extends `\\${infer R}`
? R extends `${infer P extends keyof Escape}${infer R}`
? TakeString<R, `${O}${Escape[P]}`>
: never
: T extends `${infer P}${infer R}`
? P extends '\n'
? never
: P extends '"'
? [StringToken<O>, ...Tokenize<R>]
: TakeString<R, `${O}${P}`>
: never
type EvalPrimitive<T extends Token[]> =
T extends TokenFirst<NullToken, infer R>
? EvalResult<null, R>
: T extends TokenFirst<BooleanToken<infer S>, infer R>
? EvalResult<S, R>
: T extends TokenFirst<StringToken<infer S>, infer R>
? EvalResult<S, R>
: never
type EvalArrayElements<T extends Token[], O extends unknown[] = []> =
T extends TokenFirst<SymbolToken<']'>, infer R>
? EvalResult<O, R>
: Eval<T> extends EvalResult<infer V, infer R>
? R extends TokenFirst<infer U, infer R>
? U extends SymbolToken<','>
? EvalArrayElements<R, [...O, V]>
: U extends SymbolToken<']'>
? EvalResult<[...O, V], R>
: never
: never
: never
type EvalArray<T extends Token[]> =
T extends TokenFirst<SymbolToken<'['>, infer R>
? EvalArrayElements<R>
: never
type EvalRecordEntries<T extends Token[], O extends Record<string, unknown> = {}> =
T extends TokenFirst<SymbolToken<'}'>, infer R>
? EvalResult<O, R>
: Eval<T> extends EvalResult<infer K extends string, infer R>
? R extends TokenFirst<SymbolToken<':'>, infer R>
? Eval<R> extends EvalResult<infer V, infer R>
? R extends TokenFirst<infer P, infer R>
? P extends SymbolToken<'}'>
? EvalResult<MergeRecord<O, K, V>, R>
: P extends SymbolToken<','>
? EvalRecordEntries<R, MergeRecord<O, K, V>>
: never
: never
: never
: never
: never
type EvalRecord<T extends Token[]> =
T extends TokenFirst<SymbolToken<'{'>, infer R>
? EvalRecordEntries<R>
: never
type Eval<T extends Token[]> =
| EvalPrimitive<T>
| EvalArray<T>
| EvalRecord<T>
export type Parse<T extends string> =
string extends T
? never
: Eval<Tokenize<T>> extends EvalResult<infer P, []>
? unknown extends P ? Eval<Tokenize<T>> : P
: never
Solution by hydrati #22162
// your answers
type P<T> = T extends string ? T : ''
type Nch = { n: '\n'; r: '\r'; f: '\f'; b: '\b'; }
type Igc = ' ' | Nch[keyof Nch]
type Counter = [0] | [Counter];
type Found<N, D extends Counter = [0], B extends string = ''> = N extends `${infer S}${infer L}` ? (
S | D[0] extends ',' | 0 ? { B: Parse<B>; L: Parse<L, 0>; } :
Found<L, S extends '{' | '[' ? [D] : S extends '}' | ']' ? D[0] extends Counter ? D[0] : D : D, `${B}${S}`>
) : { B: Parse<B>; L: ''; }
type PArr<N, R extends any[] = [], S extends { B: any; L: string; } = Found<N>> =
N extends '' ? R : [S['B']] extends [never] ? never : PArr<S['L'], [...R, S['B']]>
type PObj<N, R = {}> = N extends `${infer K}:${infer D}` ? PStr<K> extends infer K ? unknown extends K ? never :
Found<D> extends { B: infer B; L: infer L extends string; } ? PObj<L, unknown extends B ? R : R & Record<P<K>, B>> : {}
: never : { [I in keyof R]: R[I]; }
type PStr<N, R = ''> = N extends `"${infer N}"` ? N extends `${any}${Igc}${any}` ? unknown : (
N extends `${infer H}\\${infer K extends keyof Nch}${infer L}` ? PStr<`"${L}"`, `${P<R>}${H}${Nch[K]}`> : `${P<R>}${N}`
) : unknown
type POri<N> =
N extends `${infer K extends boolean | null}` ? K :
N extends `"${any}` ? PStr<N> :
N extends `[${infer K}]` ? Parse<K, 2> :
N extends `{${infer K}}` ? Parse<K, 3> :
never
type Parse<T, O = 1> = T extends `${Igc}${infer T}` | `${Igc}${infer T}${Igc}` | `${infer T}${Igc}` ? Parse<T, O> :
O extends 1 ? POri<T> : O extends 2 ? PArr<T> : O extends 3 ? PObj<T> : O extends 4 ? PStr<T> : T
Solution by E0SelmY4V #21755
This is a json parser implemented according to context-free grammar
json â object | array ;
object â "{" (member)? "}" ;
members â pair ( "," pair )* ;
pair â string ":" value ;
array â "[" value ( "," value )* "]" | "[]" ;
value â string | object | array | "true" | "false" | "null" ;
string â """ ( character | escape )* """ ;
character â any-Unicode-character-except-"-or-\-or-control-character ;
escape â "\" ( "" | "\" | "/" | "b" | "f" | "n" | "r" | "t" ) ;
// your answers
type Pure<T> = {
[P in keyof T]: T[P] extends object ? Pure<T[P]> : T[P];
};
type SetProperty<T, K extends PropertyKey, V> = {
[P in keyof T | K]: P extends K ? V : P extends keyof T ? T[P] : never;
};
type Token = '{' | '}' | '[' | ']' | ':' | ',' | `"${string}"` | Primitive;
type Primitive = null | true | false;
type NumberType =
| `0`
| `1`
| `2`
| `3`
| `4`
| `5`
| `6`
| `7`
| `8`
| `9`
| `-`;
type Parse<T extends string> = Pure<ParseLiteral<Tokenize<T>>[0]>;
type Tokenize<
S,
T extends Token[] = []
> = S extends `${infer First}${infer Rest}`
? First extends '{' | '}' | '[' | ']' | ':' | ','
? Tokenize<Rest, [...T, First]>
: First extends `"`
? ParseStringResult<Rest> extends [
infer Rest,
infer Token extends `"${string}"`
]
? Tokenize<Rest, [...T, Token]>
: never
: First extends `t` | `f` | `n`
? ParsePrimitiveResult<S> extends [
infer Rest,
infer Token extends `"${string}"` | null | true | false
]
? Tokenize<Rest, [...T, Token]>
: never
: First extends NumberType
? never
: First extends ` ` | `\t` | `\n`
? Tokenize<Rest, T>
: never
: T;
type ParseLiteral<T extends Token[]> = T extends [
`"${string}"` | null | true | false
]
? [ParseLiteralResult<T[0]>]
: ParseResult<T>;
type ParseResult<T extends Token[]> = T extends [
infer FirstToken,
...infer RestTokens extends Token[]
]
? FirstToken extends '{'
? ParseObjectResult<RestTokens>
: FirstToken extends '['
? ParseArrayResult<RestTokens>
: never
: never;
type ParseArrayResult<
T extends Token[],
Result extends unknown[] = []
> = T extends [infer First, ...infer RestToken extends Token[]]
? First extends ']'
? [Result, RestToken]
: First extends ','
? ParseArrayResult<RestToken, Result>
: Value<T> extends [infer value, infer vRestToken extends Token[]]
? ParseArrayResult<vRestToken, [...Result, value]>
: never
: never;
type ParseObjectResult<T extends Token[], Result = {}> = T extends [
infer First,
...infer Rest extends Token[]
]
? First extends '}'
? [Result, Rest]
: First extends ','
? ParseObjectResult<Rest, Result>
: First extends `\"${infer lexeme}\"`
? Pair<Rest, Result, lexeme> extends [
infer PResult,
infer RestToken extends Token[]
]
? ParseObjectResult<RestToken, PResult>
: never
: never
: never;
type Pair<
Rest extends Token[],
Result = {},
Key extends string = ''
> = Rest extends [infer First, ...infer RestToken extends Token[]]
? First extends ':'
? Value<RestToken> extends [infer value, infer RestToken]
? [SetProperty<Result, Key, value>, RestToken]
: never
: never
: [Result, Rest];
type Value<Rest extends Token[]> = Rest extends [
infer First,
...infer RestToken extends Token[]
]
? First extends `\"${infer value}\"`
? [value, RestToken]
: First extends '{'
? ParseObjectResult<RestToken> extends [infer VResult, infer VRest]
? [VResult, VRest]
: never
: First extends '['
? ParseArrayResult<RestToken> extends [infer VResult, infer VRest]
? [VResult, VRest]
: never
: First extends Primitive
? [First, RestToken]
: never
: never;
type ParseLiteralResult<T extends `"${string}"` | null | true | false> =
T extends `"${infer StringContent}"` ? UnescapeString<StringContent> : T;
type UnescapeString<S extends string> =
S extends `${infer First}${infer Second}${infer Rest}`
? `${First}${Second}` extends `\\n`
? `\n${UnescapeString<Rest>}`
: `${First}${Second}` extends `\\r`
? `\r${UnescapeString<Rest>}`
: `${First}${Second}` extends `\\f`
? `\f${UnescapeString<Rest>}`
: `${First}${Second}` extends `\\b`
? `\b${UnescapeString<Rest>}`
: `${First}${Second}` extends `\\t`
? `\t${UnescapeString<Rest>}`
: `${First}${Second}${UnescapeString<Rest>}`
: S;
type EscapeCharactor<S extends string> = S extends `n`
? `\n`
: S extends `r`
? `\r`
: S extends `f`
? `\f`
: S extends `b`
? `\b`
: S extends `t`
? `\t`
: S;
type ParseStringResult<
S extends string,
Result extends string = ``
> = S extends `\\${infer First}${infer Rest}`
? ParseStringResult<Rest, `${Result}${EscapeCharactor<First>}`>
: S extends `"${infer Rest}`
? [Rest, `"${Result}"`]
: S extends `\n${string}`
? never
: S extends `${infer First}${infer Rest}`
? ParseStringResult<Rest, `${Result}${First}`>
: never;
type ParsePrimitiveResult<S extends string> = S extends `true${infer Rest}`
? [Rest, true]
: S extends `false${infer Rest}`
? [Rest, false]
: S extends `null${infer Rest}`
? [Rest, null]
: never;
Solution by flyFatSeal #21318
// your answers
type Push<Arr extends readonly any[], Item > = [...Arr,Item] ;
type Pop<Arr extends readonly any[] > = Arr extends readonly [...infer R extends readonly any[],any] ? R : never ;
type Last<Arr extends readonly any[] > = Arr extends readonly [...readonly any[], infer R] ? R : never ;
type StringToNumber<Str> = Str extends `${infer R extends number}` ? R : Str ;
type TrimLeft<Str extends string> = Str extends `${' '}${infer U extends string}` ? TrimLeft<U> : Str ;
type TrimRight<Str extends string> = Str extends `${infer U extends string}${' '}` ? TrimRight<U> : Str ;
type Trim<Str extends string> = TrimLeft<TrimRight<Str>> ;
type ArrayKeys<
A extends readonly any[]> =
A extends [infer R,...infer U extends readonly any[]]
? U['length']|ArrayKeys<U>
: never ;
type NestedValues<
T extends object,
Key = T extends readonly any[] ? ArrayKeys<T> : keyof T,
Value = T[Key&keyof T]> =
Value extends Value
? Value extends [never]
? [never]
: Value extends object ? NestedValues<Value> : Value
: never ;
type NestedKeysExceptArrayKeys<
T extends object,
Key = T extends readonly any[] ? ArrayKeys<T> : keyof T> =
[Key] extends [never]
? never
:Key extends Key
? T[Key&keyof T] extends object
? (T extends readonly any[] ? never : Key)|NestedKeysExceptArrayKeys<T[Key&keyof T]>
: (T extends readonly any[] ? never : Key)
: never ;
type HasNumberKeysOrValues<
T extends object,
KeyOrValue = NestedValues<T>|NestedKeysExceptArrayKeys<T> > =
KeyOrValue extends KeyOrValue
? KeyOrValue extends string
? `${KeyOrValue}` extends `${number}`
? true
: false
: KeyOrValue extends number
? true
: false
: never ;
type NeverIfHasNumberKeysOrValues<
Input> =
Input extends string
? Input
: Input extends object
? HasNumberKeysOrValues<Input> extends false
? Input
: never
: Input ;
type UnicodeSymbols =
{
'r':'\r',
'b':'\b',
'f':'\f',
'n':'\n'
't':'\t',
} ;
type ParseUnicode<
Str extends string> =
Str extends `${infer R extends string}\\${infer S extends keyof UnicodeSymbols}${infer U extends string}`
? `${ParseUnicode<R>}${UnicodeSymbols[S]}${ParseUnicode<U>}`
: `${Str}` ;
type ExcludeUnicodeSymbols<
Str extends string,
Result extends string = '' > =
Str extends `${infer R extends string}${infer U extends string}`
? R extends NestedValues<UnicodeSymbols>
? ExcludeUnicodeSymbols<U,Result>
: ExcludeUnicodeSymbols<U,`${Result}${R}`>
: Result ;
type Brackets = '{'|'}'|'['|']' ;
type BracketRelations =
{
'}':'{',
']':'[',
} ;
type SimpleTypes =
{
'true':true,
'false':false,
'undefined':undefined,
'null':null,
} ;
type HasBrackets<
Str extends string> =
Str extends `${infer R}${infer U}`
? R extends Brackets
? true
: HasBrackets<U>
: false ;
type AreBracketsOk<
Str extends string,
BracketsStack extends readonly Brackets[]=[],
Steps extends readonly any[]=[] > =
Str extends `${infer R extends string}${infer U extends string}`
? R extends '{'|'['
? AreBracketsOk<U,Push<BracketsStack,R>,Push<Steps,any>>
: R extends '}'|']'
? BracketRelations[R] extends Last<BracketsStack>
? AreBracketsOk<U,Pop<BracketsStack>,Push<Steps,any>>
: false
: AreBracketsOk<U,BracketsStack,Push<Steps,any>>
: BracketsStack extends []
? true
: false ;
type Split<
Str extends string,
Separator extends string,
Skip extends boolean = false,
ArrMembers extends any[]=[],
Member extends string='' > =
Str extends ''
? [false,[never]]
: Str extends `${infer R extends string}${Separator}${infer U extends string}`
? R extends ''
? [false,[never]]
: AreBracketsOk<`${Member}${R}`> extends true
? Split<U,Separator,Skip,Push<ArrMembers,RoughParse<`${Member}${R}`,Skip>[1]>>
: Split<U,Separator,Skip,ArrMembers,`${Member}${R}${Separator}`>
: AreBracketsOk<`${Member}${Str}`> extends true
? [true,Push<ArrMembers,RoughParse<`${Member}${Str}`,Skip>[1]>]
: [false,[never]] ;
type GetEntries<
Parts extends readonly string[],
Entries extends readonly [string,string][]=[] > =
Parts extends readonly [infer R extends string,...infer U extends readonly string[]]
? Split<R,':',true> extends [false,[never]]
? [false,[never]]
: Split<R,':',true>[1] extends [string,string]
? GetEntries<U,[...Entries,Split<R,':',true>[1]]>
: [false,[never]]
: [true,Entries] ;
type ObjectFromEntries<
Entries extends readonly [string,string][],
Result extends object = {}> =
Entries extends readonly [infer R extends [string,string],...infer U extends [string,string][]]
? ObjectFromEntries<U,Result&{[J in R[0]] : R[1]}>
: Result;
type ParseArr<
Str extends string> =
Str extends `[${infer R extends string}]`
? R extends ''
? [true,[]]
: Split<R,','>
: [false,[never]] ;
type ParseObj<
Str extends string,
SplitedObj extends readonly [boolean,any] =
Str extends `{${infer R extends string}}`
? R extends ''
? [true,[]]
: Split<R,',',true>
: [false,[never]] ,
Entries extends readonly [boolean,any] = SplitedObj[0] extends true
? GetEntries<SplitedObj[1]>
: SplitedObj ,
Result extends object =
Entries[0] extends false
? never
: ObjectFromEntries<Entries[1]>
> =
[Result] extends [never]
? [false,[never]]
:[true,{[J in keyof Result] : RoughParse<Result[J]&string>[1]}] ;
type RoughParse<
Input extends string,
Skip extends boolean =
false,
Trimmed extends string =
Trim<Input> > =
Skip extends true
? [true,Input]
: HasBrackets<Trimmed> extends false
? [true,Input]
: Trimmed extends `${infer R extends string}${string}`
? R extends '{'
? ParseObj<Trimmed>
: R extends '['
? ParseArr<Trimmed>
: [false,never]
: never;
type RoughParsedOrNever<
T extends string,
Result=RoughParse<T>[1],
> =
Result extends object
? Result extends [never]
? never
: [never] extends NestedValues<Result>
? never
: Result
: Result ;
type SetTypeToPrimitive<
Str extends string,
Trimmed =
Trim<Str> > =
Trimmed extends `\"${infer R}\"`
? R
: Trimmed extends keyof SimpleTypes
? SimpleTypes [Trimmed]
: StringToNumber<Trimmed> ;
type SetTypes<
T> =
T extends string
? SetTypeToPrimitive<T>
: T extends readonly any[]
? T extends readonly [infer R,...infer U]
? [SetTypes<R>,...SetTypes<U>]
: []
: T extends object
? {[J in string&keyof T as SetTypes<J>] : SetTypes<T[J]>}
: T ;
type Parse<
Input extends string> =
NeverIfHasNumberKeysOrValues<SetTypes<RoughParsedOrNever<ParseUnicode<ExcludeUnicodeSymbols<Input>>>>> ;
Solution by justBadProgrammer #17145
type Parse<S extends string> = ParseValue<S> extends [infer L extends string, infer V] ? Peek<S, L> extends '' ? V : never : never
type ParseValue<S extends string, L extends string = ''>
= S extends `${L}${infer C}${any}`
? C extends ' ' | '\t' | '\n' ? ParseValue<S, `${L}${C}`>
: C extends '{' ? ParseObject<S, `${L}{`>
: C extends '[' ? ParseArray<S, `${L}[`>
: C extends 'n' ? S extends `${L}null${any}` ? [`${L}null`, null] : []
: C extends 't' ? S extends `${L}true${any}` ? [`${L}true`, true] : []
: C extends 'f' ? S extends `${L}false${any}` ? [`${L}false`, false] : []
: C extends '"' ? ParseString<S, `${L}"`>
: C extends '-'
? S extends `${L}${C}${infer C2}${any}`
? C2 extends Digit ? ParseNumber<S, `${L}${C}${C2}`, `${C}${C2}`>
: []
: []
: C extends Digit ? ParseNumber<S, `${L}${C}`, C>
: []
: []
type ParseString<S extends string, L extends string = '"', Result extends string = ''>
= S extends `${L}${infer C}${any}`
? C extends '"' ? [`${L}"`, Result]
: C extends '\n' | '\r' | '\t' ? [] // those chars must be escape
: C extends `\\`
? S extends `${L}\\${infer C2}${any}`
? C2 extends '\\' ? ParseString<S, `${L}\\\\`, `${Result}\\`>
: C2 extends '"' ? ParseString<S, `${L}\\"`, `${Result}\"`>
: C2 extends 'b' ? ParseString<S, `${L}\\b`, `${Result}\b`>
: C2 extends 'f' ? ParseString<S, `${L}\\f`, `${Result}\f`>
: C2 extends 'n' ? ParseString<S, `${L}\\n`, `${Result}\n`>
: C2 extends 'r' ? ParseString<S, `${L}\\r`, `${Result}\r`>
: C2 extends 't' ? ParseString<S, `${L}\\t`, `${Result}\t`>
: C2 extends 'u'
? S extends `${L}\\u${infer E}${infer F}${infer G}${infer H}${any}`
? E | F | G | H extends Hex
? ParseString<S, `${L}\\u${E}${F}${G}${H}`, `${Result}${GetUnicode<`${E}${F}${G}${H}`>}`>
: [] // expecting 4 hex chars
: [] // unexpected escape sequence
: [] // unexpected escape sequence
: [] // unexpected escape sequence
: ParseString<S, `${L}${C}`, `${Result}${C}`>
: [] // expecting token
type ParseObject<S extends string, L extends string = '{', Result extends object = {}>
= S extends `${L}${infer C}${any}`
? C extends ' ' | '\t' | '\n' ? ParseObject<S, `${L}${C}`, Result>
: C extends '}' ? Result extends {} ? [`${L}}`, {}] : []
: C extends '"'
? ParseString<S, `${L}"`> extends [infer L extends string, infer P extends string]
? P extends keyof Result ? [] // duplicated property name
: ParseObjectColon<S, L, P, Result>
: [] // expecting Name
: [] // expecting "
: [] // expecting "
type ParseObjectColon<S extends string, L extends string, P extends string, Result extends object>
= S extends `${L}${infer C}${any}`
? C extends ' ' | '\t' | '\n' ? ParseObjectColon<S, `${L}${C}`, P, Result>
: C extends ':'
? ParseValue<S, `${L}:`> extends [infer L extends string, infer V]
? ParseObjectValue<S, L, P, V, Result>
: [] // expecting Value
: [] // expecting :
: [] // expecting :
type ParseObjectValue<S extends string, L extends string, P extends string, V, Result extends object>
= S extends `${L}${infer C}${any}`
? C extends ' ' | '\t' | '\n' ? ParseObjectValue<S, `${L}${C}`, P, V, Result>
: C extends ',' ? ParseObject<S, `${L},`, {[K in keyof Result | P]: K extends keyof Result ? Result[K] : V}>
: C extends '}' ? [`${L}}`, {[K in keyof Result | P]: K extends keyof Result ? Result[K] : V}]
: [] // expecting , or }
: [] // expecting , or }
type ParseArray<S extends string, L extends string = '[', Result extends unknown[] = []>
= S extends `${L}${infer C}${any}`
? C extends ' ' | '\t' | '\n' ? ParseArray<S, `${L}${C}`, Result>
: C extends ']' ? Result extends [] ? [`${L}]`, []] : []
: ParseValue<S, L> extends [infer L extends string, infer V]
? ParseArrayValue<S, L, V, Result>
: [] // expecting ]
: [] // expecting ]
type ParseArrayValue<S extends string, L extends string, V, Result extends unknown[]>
= S extends `${L}${infer C}${any}`
? C extends ' ' | '\t' | '\n' ? ParseArrayValue<S, `${L}${C}`, V, Result>
: C extends ',' ? ParseArray<S, `${L},`, [...Result, V]>
: C extends ']' ? [`${L}]`, [...Result, V]]
: [] // expecting , or ]
: [] // expecting , or ]
type ParseNumber<S extends string, L extends string = '', Result extends string = ''>
= S extends `${L}${infer C}${any}`
? C extends Digit ? ParseNumber<S, `${L}${PeekDigits<S, L>}`, `${Result}${PeekDigits<S, L>}`>
: C extends '.' ? Result extends `${any}.${any}` ? [] : ParseNumber<S, `${L}.`, `${Result}.`>
: C extends 'e' | 'E'
? S extends `${L}${C}-${Digit}${any}` ? [`${L}${C}-${PeekDigits<S, `${L}${C}-`>}`, ParseExponent<Result, `-${PeekDigits<S, `${L}${C}-`>}`>]
: S extends `${L}${C}+${Digit}${any}` ? [`${L}${C}+${PeekDigits<S, `${L}${C}+`>}`, ParseExponent<Result, PeekDigits<S, `${L}${C}+`>>]
: S extends `${L}${C}${Digit}${any}` ? [`${L}${C}${PeekDigits<S, `${L}${C}`>}`, ParseExponent<Result, PeekDigits<S, `${L}${C}`>>]
: [L, ParseExponent<Result, '0'>]
: [L, ParseExponent<Result, '0'>]
: [L, ParseExponent<Result, '0'>] // expecting token
type NormalizeExponent<Mantissa extends string, Exponent extends string>
= Exponent extends `0` | '-0'
? Mantissa extends `${infer I}.${infer F}0` ? NormalizeExponent<`${I}.${F}`, Exponent>
: Mantissa
: Exponent extends `-${infer E extends bigint}`
? NormalizeExponent<
Mantissa extends `${infer I}.${infer F}`
? I extends Digit ? `0.${I}${F}`
: I extends `${infer I1}${Digit}` ? `${I1}.${TrimStart<I, I1>}${F}`
: Mantissa
: Mantissa extends `${infer I}0` ? I
: Mantissa extends `${infer I}${Digit}` ? `${I}.${TrimStart<Mantissa, I>}`
: Mantissa
, `-${MinusOne<`${E}`>}`>
: NormalizeExponent<
Mantissa extends `${infer I}.${infer F}`
? F extends Digit ? `${I}${F}`
: F extends `${infer F1}${infer F2}` ? `${I}${F1}.${F2}`
: Mantissa
: `${Mantissa}0`
, MinusOne<Exponent>>
type NegSciForm<Mantissa extends string, Exponent extends string = '0'>
= [Mantissa & `0.${any}`] extends [never]
? Exponent extends '0' ? Mantissa : `${Mantissa}e-${Exponent}`
: Mantissa extends `0.${Digit}` ? NegSciForm<TrimStart<Mantissa, '0.'>, PlusOne<Exponent>>
: Mantissa extends `0.${infer F1}${infer F2}` ? NegSciForm<`${F1}.${F2}`, PlusOne<Exponent>>
: Mantissa
type PosSciForm<Mantissa extends string, Exponent extends string = '0'>
= Mantissa extends Digit | `${Digit}.${any}`
? Exponent extends '0' ? Mantissa : `${Mantissa}e+${Exponent}`
: Mantissa extends `${infer I}.${infer F}`
? PosSciForm<I extends `${infer I1}${Digit}` ? `${I1}.${TrimStart<I, I1>}${F}` : never, PlusOne<Exponent>>
: Mantissa extends `${infer I}0` ? PosSciForm<I, PlusOne<Exponent>>
: Mantissa extends `${infer I}${Digit}` ? PosSciForm<`${I}.${TrimStart<Mantissa, I>}`, PlusOne<Exponent>>
: Mantissa
type ParseExponent<Mantissa extends string, Exponent extends string, Normalized extends string = NormalizeExponent<Mantissa, Exponent>>
= Normalized extends `0.000000${any}`
? NegSciForm<Normalized> extends infer N extends string ? Num<N> : never
: Normalized extends `${any}.${any}`
? Normalized extends `${any}${any}${any}${any}${any}${any}${any}${any}${any}${any}${any}${any}${any}${any}${any}${any}${any}${any}${any}${any}${any}${any}${any}.${any}`
? PosSciForm<Normalized> extends infer N extends string ? Num<N> : never
: Num<Normalized>
: Normalized extends `${any}${any}${any}${any}${any}${any}${any}${any}${any}${any}${any}${any}${any}${any}${any}${any}${any}${any}${any}${any}${any}${any}${any}`
? PosSciForm<Normalized> extends infer N extends string ? Num<N> : never
: Num<Normalized>
type PlusOne<N extends string, Result extends string = ''>
= N extends `${infer L}9` ? L extends '' ? `10${Result}` : PlusOne<L, `0${Result}`>
: N extends `${infer L}8` ? `${L}9${Result}`
: N extends `${infer L}7` ? `${L}8${Result}`
: N extends `${infer L}6` ? `${L}7${Result}`
: N extends `${infer L}5` ? `${L}6${Result}`
: N extends `${infer L}4` ? `${L}5${Result}`
: N extends `${infer L}3` ? `${L}4${Result}`
: N extends `${infer L}2` ? `${L}3${Result}`
: N extends `${infer L}1` ? `${L}2${Result}`
: N extends `${infer L}0` ? `${L}1${Result}`
: never
type MinusOne<N extends string, Result extends string = ''>
= N extends `${infer L}0` ? L extends '1' ? `9${Result}` : MinusOne<L, `9${Result}`>
: N extends `${infer L}1` ? `${L}0${Result}`
: N extends `${infer L}2` ? `${L}1${Result}`
: N extends `${infer L}3` ? `${L}2${Result}`
: N extends `${infer L}4` ? `${L}3${Result}`
: N extends `${infer L}5` ? `${L}4${Result}`
: N extends `${infer L}6` ? `${L}5${Result}`
: N extends `${infer L}7` ? `${L}6${Result}`
: N extends `${infer L}8` ? `${L}7${Result}`
: N extends `${infer L}9` ? `${L}8${Result}`
: never
type Peek<S extends string, L extends string = ''>
= S extends `${L}${infer C}${any}` ? C extends ' ' | '\t' | '\n' ? Peek<S, `${L}${C}`> : `${C}${L}` : ''
type PeekDigits<S extends string, L extends string = '', Result extends string = ''>
= S extends `${L}${infer C}${any}` ? C extends Digit ? PeekDigits<S, `${L}${C}`, `${Result}${C}`> : Result : Result
type TrimStart<S extends string, Start extends string> = S extends `${Start}${infer End}` ? End : ''
type Num<S extends string> = S extends `${infer N extends number}` ? number extends N ? never : N : never
type Digit = '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9'
type Hex = Digit | 'a' | 'b' | 'c' | 'd' | 'e' | 'f'
type GetUnicode<H extends string> = Unicode extends GetPadStart<H, `${infer C}${any}`> ? C : never
type GetPadStart<H extends string, End extends string, Result extends string = ''>
= H extends `${infer F extends keyof PadStart}${infer R}` ? GetPadStart<R, End, PadStart<Result>[F]>
: `${Result}${End}`
type PadStart<H extends string = '', H10 extends string = `${H}${H}${H}${H}${H}${H}${H}${H}${H}${H}${H}${H}${H}${H}${H}${H}`> = {
'0': `${H10}`,
'1': `${H10}${any}`,
'2': `${H10}${any}${any}`,
'3': `${H10}${any}${any}${any}`,
'4': `${H10}${any}${any}${any}${any}`,
'5': `${H10}${any}${any}${any}${any}${any}`,
'6': `${H10}${any}${any}${any}${any}${any}${any}`,
'7': `${H10}${any}${any}${any}${any}${any}${any}${any}`,
'8': `${H10}${any}${any}${any}${any}${any}${any}${any}${any}`,
'9': `${H10}${any}${any}${any}${any}${any}${any}${any}${any}${any}`,
'a': `${H10}${any}${any}${any}${any}${any}${any}${any}${any}${any}${any}`,
'b': `${H10}${any}${any}${any}${any}${any}${any}${any}${any}${any}${any}${any}`,
'c': `${H10}${any}${any}${any}${any}${any}${any}${any}${any}${any}${any}${any}${any}`,
'd': `${H10}${any}${any}${any}${any}${any}${any}${any}${any}${any}${any}${any}${any}${any}`,
'e': `${H10}${any}${any}${any}${any}${any}${any}${any}${any}${any}${any}${any}${any}${any}${any}`,
'f': `${H10}${any}${any}${any}${any}${any}${any}${any}${any}${any}${any}${any}${any}${any}${any}${any}`,
}
type Unicode = '\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\u0008\u0009\u000a\u000b\u000c\u000d....'
// full code in playground
Solution by teamchong #11695
type Parse<JSON extends string>
= ParseValue<TrimLeft<JSON>> extends [infer Parsed, infer Tail extends string]
? [Parsed] extends [never]
? never
: TrimLeft<Tail> extends ''
? Parsed
: never
: never
type TrimLeft<JSON extends string> = JSON extends `${' ' | '\n' | '\t'}${infer R}`
? TrimLeft<R>
: JSON
type ParseValue<JSON extends string>
= JSON extends `undefined${infer R}` ? [undefined, TrimLeft<R>]
: JSON extends `null${infer R}` ? [null, TrimLeft<R>]
: JSON extends `true${infer R}` ? [true, TrimLeft<R>]
: JSON extends `false${infer R}` ? [false, TrimLeft<R>]
: JSON extends `"${infer Str}"${infer R}` ? [ParseString<Str>, TrimLeft<R>]
: JSON extends `[${infer R}` ? TrimLeft<R> extends `]${infer R}`
? [[], TrimLeft<R>]
: ParseArray<`,${TrimLeft<R>}`>
: JSON extends `{${infer R}` ? TrimLeft<R> extends `}${infer R}`
? [{}, TrimLeft<R>]
: ParseObject<`,${TrimLeft<R>}`>
: never
type ParseString<S extends string>
= S extends `${infer L}\\${infer C extends keyof EscChars}${infer R}`
? ParseString<`${L}${EscChars[C]}${R}`>
: S
type EscChars = { n: '\n', t: '\t', r: '\r', b: '\b', f: '\f' }
type ParseArray<JSON extends string, Arr extends any[] = []>
= JSON extends `]${infer R}`
? [Arr, TrimLeft<R>]
: JSON extends `,${infer R}`
? ParseValue<TrimLeft<R>> extends [infer Value, infer R extends string]
? [Value] extends [never]
? never
: ParseArray<TrimLeft<R>, [...Arr, Value]>
: never
: never
type ParseObject<JSON extends string, Obj extends object = {}>
= JSON extends `}${infer R}`
? [Merge<Obj>, TrimLeft<R>]
: JSON extends `,${infer R}`
? ParseKey<TrimLeft<R>> extends [infer Key extends string, infer R]
? R extends `:${infer R}`
? ParseValue<TrimLeft<R>> extends [infer Value, infer R extends string]
? ParseObject<TrimLeft<R>, Obj & { [K in Key]: Value }>
: never
: never
: never
: never
type ParseKey<JSON extends string>
= JSON extends `"${infer Key}"${infer R}`
? [ParseString<Key>, TrimLeft<R>]
: never
type Merge<O> = { [K in keyof O]: O[K] }
The solution is designed to pass more complicated test cases than there are provided. Also, it's really easy to extend it to parse Numbers as well - not sure why they have been excluded from the problem in the first place
Solution by Alexsey #11692
// your answers
type TrimBase<T extends string, R extends string = ' '> = T extends `${R}${infer S}`
? TrimBase<S, R>
: T extends `${infer S}${R}`
? TrimBase<S, R>
: T
type Trim<T extends string> = TrimBase<TrimBase<T>, '"'>
type ParserObject<
T extends string,
R extends Record<string, any> = {},
K extends string = '',
V extends string = '',
F extends boolean = false,
L extends unknown[] = [],
> = T extends `${infer S}${infer E}`
? F extends false
? S extends ':'
? ParserObject<E, R, Trim<K>, V, true, L>
: ParserObject<E, R, `${K}${S}`, V, F, L>
: S extends ','
? L extends []
? ParserObject<E, { [P in keyof R]: R[P] } & { [P in K]: Parser<V> }, '', '', false, L>
: ParserObject<E, R, K, `${V}${S}`, F, L>
: S extends '[' | '{'
? ParserObject<E, R, K, `${V}${S}`, F, [...L, unknown]>
: S extends ']' | '}'
? L extends [unknown, ...infer B]
? ParserObject<E, R, K, `${V}${S}`, F, B>
: ParserObject<E, R, K, `${V}${S}`, F, L>
: ParserObject<E, R, K, `${V}${S}`, F, L>
: K extends ''
? { [P in keyof R]: R[P] }
: ParserObject<'', { [P in keyof R]: R[P] } & { [P in K]: Parser<V> }, '', '', false, L>
type ParserArray<
T extends string,
R extends string[] = [],
V extends string = '',
L extends unknown[] = [],
> = T extends `${infer S}${infer E}`
? S extends ','
? L extends []
? ParserArray<E, [...R, Parser<V>], '', L>
: ParserArray<E, R, `${V}${S}`, L>
: S extends '[' | '{'
? ParserArray<E, R, `${V}${S}`, [...L, unknown]>
: S extends '}' | ']'
? L extends [unknown, ...infer B]
? ParserArray<E, R, `${V}${S}`, B>
: ParserArray<E, R, `${V}${S}`, L>
: ParserArray<E, R, `${V}${S}`, L>
: [...R, Parser<V>]
type ParserHelper<T extends string> = T extends `{${infer S}}`
? ParserObject<Trim<S>>
: T extends `[${infer S}]`
? ParserArray<S>
: T extends 'true'
? true
: T extends 'false'
? false
: T extends 'null'
? null
: // Numbers and Unicode escape (\uxxxx) in JSON can be ignored. You needn't to parse them.
T
type Parser<T extends string> = ParserHelper<Trim<T>>
type A =
Parser<' { "asdasd ":{} , " a123 " : true,"b123":{"b1acads": 1," b2":{"aasd ":false},"b3asda":2},"c":3,"d":{"d":null}}'>
// type A = {
// 'asdasd ': {}
// ' a123 ': true
// b123: {
// b1acads: '1'
// ' b2': {
// 'aasd ': false
// }
// b3asda: '2'
// }
// c: '3'
// d: {
// d: null
// }
// }
type B = Parser<'[ 1 ,true, false,null ,{ },{ " a ":1,"b":{"b":"2"}},2,3]'>
// type B = [
// '1',
// true,
// false,
// null,
// {},
// {
// 'a ': '1'
// b: {
// b: '2'
// }
// },
// '2',
// '3',
// ]
Solution by ZangYuSong #6959
// your answers
type Pure<T> = {
[P in keyof T]: T[P] extends object ? Pure<T[P]> : T[P]
}
type SetProperty<T, K extends PropertyKey, V> = {
[P in (keyof T) | K]: P extends K ? V : P extends keyof T ? T[P] : never
}
type NumberToken = '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' | '-';
type BeginObjectToken = "{";
type EndObjectToken = "}";
type BeginArrayToken = "[";
type EndArrayToken = "]";
type SepColonToken = ":";
type SepCommaToken = ",";
type DoubleQuoteToken = "\"";
type StringToken = `\"${string}\"`;
type PrimitiveToken = StringToken | null | true | false;
type SyntaxToken = BeginObjectToken | EndObjectToken | BeginArrayToken | EndArrayToken | SepColonToken | SepCommaToken;
type Token = SyntaxToken | PrimitiveToken;
type ToVal<F extends PrimitiveToken> = F extends `\"${infer S}\"` ? S : F;
type ToEscape<S extends string> = S extends `'` ? '\'' :
S extends `"` ? '\"' :
S extends `n` ? '\n' :
S extends `r` ? '\r' :
S extends `f` ? '\f' :
S extends `b` ? '\b' :
S extends `t` ? '\t' : S;
type GetString<S extends string, R extends string = ""> = S extends `\\${infer F}${infer T}` ? GetString<T, `${R}${ToEscape<F>}`>
: S extends `${infer F}${infer T}` ? (F extends DoubleQuoteToken ? [T, `${R}${F}`] : F extends "\n" ? never : GetString<T, `${R}${F}`>)
: never;
type ToPrimitive<T extends string> = T extends `true` ? true : T extends 'false' ? false : T extends 'null' ? null : never;
type GetPrimitive<S extends string, R extends string = ""> = S extends `${infer F}${infer T}` ? (`${R}${F}` extends 'true' | 'false' | 'null' ? [T, ToPrimitive<`${R}${F}`>] : GetPrimitive<T, `${R}${F}`>) : never;
type ExpectToken = SepCommaToken | EndArrayToken;
// æåæ°įŧ
type ParseArrayResult<T extends any, R extends any[] = [], E extends any = PrimitiveToken | EndArrayToken | BeginArrayToken | BeginObjectToken> = T extends [infer F, ...infer S] ?
(F extends E ?
( // æ°įŧįŧæ
F extends EndArrayToken ? [R, S] :
// åæ°įŧ
F extends BeginArrayToken ? (ParseArrayResult<S> extends [infer F1, infer F2] ? ParseArrayResult<F2, [...R, F1], ExpectToken> : never) :
// ååŊđ蹥
F extends BeginObjectToken ? (ParseObjectResult<S> extends [infer F1, infer F2] ? ParseArrayResult<F2, [...R, F1], ExpectToken> : never) :
// éå·æ čŊ
F extends SepCommaToken ? ParseArrayResult<S, R, PrimitiveToken | BeginArrayToken | BeginObjectToken> :
// åž
F extends PrimitiveToken ? ParseArrayResult<S, [...R, ToVal<F>], ExpectToken> : never
) : never
) : never;
// æååŊđ蹥
type ParseObjectResult<T extends any, R extends any = {}, E extends any = EndObjectToken | StringToken, K extends string = ''> = T extends [infer F, ...infer S] ?
(
// æŊåĶįŽĶåéĒææ čŊ
F extends E ? (
// æååž
K extends StringToken ? (
// : æ čŊįŽĶ
F extends SepColonToken ? ParseObjectResult<S, R, PrimitiveToken | BeginArrayToken | BeginObjectToken, K> :
// æŪéåž
F extends PrimitiveToken ? ParseObjectResult<S, SetProperty<R, ToVal<K>, ToVal<F>>, SepCommaToken | EndObjectToken> :
// æ°įŧ
F extends BeginArrayToken ? (ParseArrayResult<S> extends [infer F1, infer F2] ? ParseObjectResult<F2, SetProperty<R, ToVal<K>, F1>, SepCommaToken | EndObjectToken> : never) :
// ååŊđ蹥
F extends BeginObjectToken ? (ParseObjectResult<S> extends [infer F1, infer F2] ? ParseObjectResult<F2, SetProperty<R, ToVal<K>, F1>, SepCommaToken | EndObjectToken> : never) :
never
) : (
// , token
F extends SepCommaToken ? ParseObjectResult<S, R, StringToken, ''> :
// key token
F extends StringToken ? (ParseObjectResult<S, R, SepColonToken, F>) :
// } end object
F extends EndObjectToken ? [R, S] : never
)
) : never
) : never;
type ParseResult<K extends Token[]> = K extends [infer F, ...infer S] ? F extends BeginObjectToken ? ParseObjectResult<S> : F extends BeginArrayToken ? ParseArrayResult<S> : never : never;
type Tokenize<S, T extends any[] = []> = S extends `${infer F}${infer N}` ?
F extends SyntaxToken ? Tokenize<N, [...T, F]> :
F extends DoubleQuoteToken ? (GetString<N, F> extends [infer A, infer B] ? Tokenize<A, [...T, B]> : never) :
F extends 't' | 'f' | 'n' ? (GetPrimitive<S> extends [infer A, infer B] ? Tokenize<A, [...T, B]> : never) :
F extends NumberToken ? never : Tokenize<N, T> : T;
type ParseLiteral<T extends Token[]> = T extends Token[] ? T extends [PrimitiveToken] ? [ToVal<T[0]>] : ParseResult<T> : never;
type Parse<T extends string> = Pure<ParseLiteral<Tokenize<T>>[0]>
Solution by venusliang #6457
//My answer is only for the test cases
type Parse<T extends string> = Eval<T> extends [infer V, infer U] ? V : never
type Eval<T>
= T extends `${' '|'\n'}${infer U}` ? Eval<U>
: T extends `true${infer U}` ? [true, U]
: T extends `false${infer U}` ? [false, U]
: T extends `null${infer U}` ? [null, U]
: T extends `"${infer U}` ? EvalString<U>
: T extends `${'['}${infer U}` ? EvalArray<U>
: T extends `${'{'}${infer U}` ? EvalObject<U>
: false
type Escapes = {r:'\r', n:'\n', b:'\b', f:'\f'}
type EvalString<T, S extends string = ''>
= T extends `"${infer U}` ? [S, U]
: (T extends `\\${infer C}${infer U}` ? C extends keyof Escapes ? [C, U] : false : false) extends [infer C, infer U]
? EvalString<U, `${S}${C extends keyof Escapes ? Escapes[C] : never}`>
: T extends `${infer C}${infer U}` ? EvalString<U, `${S}${C}`>
: false
type EvalArray<T, A extends any[] = []>
= T extends `${' '|'\n'}${infer U}` ? EvalArray<U, A>
: T extends `]${infer U}` ? [A, U]
: T extends `,${infer U}` ? EvalArray<U, A>
: Eval<T> extends [infer V, infer U] ? EvalArray<U, [...A, V]>
: false
type EvalObject<T, K extends string = '', O = {}>
= T extends `${' '|'\n'}${infer U}` ? EvalObject<U, K, O>
: T extends `}${infer U}` ? [O, U]
: T extends `,${infer U}` ? EvalObject<U, K, O>
: T extends `"${infer U}` ? Eval<`"${U}`> extends [`${infer KK}`, infer UU] ? EvalObject<UU, KK, O> : false
: T extends `:${infer U}` ? Eval<U> extends [infer V, infer UU] ? EvalObject<UU, '', Merge<{[P in K]: V} & O>> : false
: false
type Merge<T> = {[P in keyof T]: T[P]}
Solution by okayu29 #6329
/**
* JSON Subset Parser, in Types
* By Hydrogen (https://github.com/hyroge)
*/
interface Token {
typ: "LCurly" | "RCurly" | "LBracket" | "RBracket" | "String" | "Comma" | "Colon" | "Keyword" | "Number"
inner?: string
}
type Pure<T> = T extends object ? {
[P in keyof T] : Pure<T[P]>
} : T
type Alpha = '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 TakeString<T extends string, S extends string = ''> = T extends `${infer P}${infer E}` ? (
P extends '\\' ? (
E extends `${infer R}${infer F}` ? (
R extends '"' ? (
TakeString<F, `${S}\"`>
) : (
R extends '\\' ? (
TakeString<F, `${S}\\`>
) : (
R extends '/' ? (
TakeString<F, `${S}/`>
) : (
R extends 'b' ? (
TakeString<F, `${S}\b`>
) : (
R extends 'f' ? (
TakeString<F, `${S}\f`>
) : (
R extends 'n' ? (
TakeString<F, `${S}\n`>
) : (
R extends 'r' ? (
TakeString<F, `${S}\r`>
) : (
R extends 't' ? (
TakeString<F, `${S}\t`>
) : 0
)
)
)
)
)
)
)
) : never
) : (
P extends '"' ? (
[{typ: "String", inner: S}, E]
) : (
P extends '\n' ? (
never
) : (
TakeString<E, `${S}${P}`>
)
)
)
) : never
type TakeKeyword<T, S extends string = ''> = T extends `${infer P}${infer E}` ? (
P extends Alpha ? (
TakeKeyword<E, `${S}${P}`>
) : (
S extends '' ? (
never
) : (
[{typ: "Keyword", inner: S}, T]
)
)
) : (
S extends '' ? (
never
) : (
[{typ: "Keyword", inner: S}, T]
)
)
type Tokenize<T extends string, S extends Token[] = []> = T extends `${infer P}${infer E}` ? (
P extends '\r' | '\t' | ' ' | '\n' ? (
Tokenize<E, S>
) : (
(
P extends '{' ? (
Tokenize<E, [...S, { typ: "LCurly" }]>
) : (
P extends '}' ? (
Tokenize<E, [...S, { typ: "RCurly" }]>
) : (
P extends '[' ? (
Tokenize<E, [...S, { typ: "LBracket" }]>
) : (
P extends ']' ? (
Tokenize<E, [...S, { typ: "RBracket" }]>
) : (
P extends ',' ? (
Tokenize<E, [...S, { typ: "Comma" }]>
) : (
P extends ':' ? (
Tokenize<E, [...S, { typ: "Colon" }]>
) : (
P extends '"' ? (
TakeString<E> extends [Token, string] ? (
Tokenize<TakeString<E>[1], [...S, TakeString<E>[0]]>
) : never
) : (
P extends Alpha ? (
TakeKeyword<T> extends [Token, string] ? (
Tokenize<TakeKeyword<T>[1], [...S, TakeKeyword<T>[0]]>
) : never
) : (
never
)
)
)
)
)
)
)
)
)
)
) : S
type SetProperty<T , K extends PropertyKey, V> = {
[P in (keyof T) | K]: P extends K ? V : P extends keyof T ? T[P] : never
}
type ParseRecordImpl<T extends Token[], S = {}> = (
ParsePair<T> extends never ? (
never
) : (
TakeToken<ParsePair<T>[1]> extends never ? (
never
) : (
TakeToken<ParsePair<T>[1]>[0]['typ'] extends 'RCurly' ? (
[SetProperty<S, ParsePair<T>[0][0], ParsePair<T>[0][1]>, TakeToken<ParsePair<T>[1]>[1]]
) : (
TakeToken<ParsePair<T>[1]>[0]['typ'] extends 'Comma' ? (
ParseRecordImpl<TakeToken<ParsePair<T>[1]>[1], SetProperty<S, ParsePair<T>[0][0], ParsePair<T>[0][1]>>
) : never
)
)
)
)
type ParseRecord<T extends Token[]> = T extends [infer P, ...(infer E)] ? (
P extends Token ? (
E extends Token[] ? (
P['typ'] extends 'RCurly' ? (
[{}, E]
) : ParseRecordImpl<T, {}>
) : never
) : never
) : never
type ParsePair<T extends Token[]> = ParseString<T> extends never ? (
ParseString<T>
) : (
TakeToken<ParseString<T>[1]> extends never ? (
never
) : (
TakeToken<ParseString<T>[1]>[0]['typ'] extends 'Colon' ? (
ParseLiteral<TakeToken<ParseString<T>[1]>[1]> extends never ? (
never
) : (
[
[ParseString<T>[0], ParseLiteral<TakeToken<ParseString<T>[1]>[1]>[0]],
ParseLiteral<TakeToken<ParseString<T>[1]>[1]>[1]
]
)
) : never
)
)
type TakeToken<T extends Token[]> = T extends [infer P, ...(infer S)] ? (
[P, S] extends [Token, Token[]] ? (
[P, S]
) : never
) : never
type ParseArrayImpl<T extends Token[], S extends unknown[] = []> = (
ParseLiteral<T> extends never ? (
never
) : (
TakeToken<ParseLiteral<T>[1]> extends never ? (
never
) : (
TakeToken<ParseLiteral<T>[1]>[0]['typ'] extends 'Comma' ? (
ParseArrayImpl<TakeToken<ParseLiteral<T>[1]>[1], [...S, ParseLiteral<T>[0]]>
) : (
TakeToken<ParseLiteral<T>[1]>[0]['typ'] extends 'RBracket' ? (
[[...S, ParseLiteral<T>[0]], TakeToken<ParseLiteral<T>[1]>[1]]
) : never
)
)
)
)
type ParseArray<T extends Token[]> = (
T extends [infer P, ...(infer E)] ? (
[P, E] extends [Token, Token[]] ? (
[P, E][0]['typ'] extends 'RBracket' ? (
[[], E]
) : ParseArrayImpl<T, []>
) : never
) : never
)
type ParseKeyword<T extends Token[]> = (
TakeToken<T> extends never ? never : (
TakeToken<T>[0]['typ'] extends 'Keyword' ? (
Exclude<TakeToken<T>[0]['inner'], undefined> extends 'true' ? (
[true, TakeToken<T>[1]]
) : (
Exclude<TakeToken<T>[0]['inner'], undefined> extends 'false' ? (
[false, TakeToken<T>[1]]
) : (
Exclude<TakeToken<T>[0]['inner'], undefined> extends 'null' ? (
[null, TakeToken<T>[1]]
) : never
)
)
) : never
)
)
type ParseString<T extends Token[]> = (
TakeToken<T> extends never ? never : (
TakeToken<T>[0]['typ'] extends 'String' ? (
[Exclude<TakeToken<T>[0]['inner'], undefined>, TakeToken<T>[1]]
) : never
)
)
type ParseNumber<T extends Token[]> = (
TakeToken<T> extends never ? never : (
TakeToken<T>[0]['typ'] extends 'Number' ? (
TakeToken<T>[0]
) : never
)
)
type ParseRoot<T extends Token[]> = (
TakeToken<T> extends never ? never : (
TakeToken<T>[0]['typ'] extends 'LCurly' ? (
ParseRecord<TakeToken<T>[1]>
) : (
TakeToken<T>[0]['typ'] extends 'LBracket' ? (
ParseArray<TakeToken<T>[1]>
) : never
)
)
)
type ParseLiteral<T extends Token[]> = (
| ParseRoot<T>
| ParseString<T>
| ParseKeyword<T>
| ParseNumber<T>
)
//
// support data types:
// - `boolean` (`true` `false`)
// - `string` (`"\\r\\n"`)
// - `object` & `array`
// - `null` (`null`)
//
type Parse<T extends string> = Pure<ParseLiteral<Tokenize<T>>[0]>
Solution by hydrati #6310