Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

「重学TS 2.0 」TS 练习题第二十九题 #48

Open
semlinker opened this issue Sep 21, 2021 · 24 comments
Open

「重学TS 2.0 」TS 练习题第二十九题 #48

semlinker opened this issue Sep 21, 2021 · 24 comments

Comments

@semlinker
Copy link
Owner

实现一个 ToPath 工具类型,用于把属性访问(.[])路径转换为元组的形式。具体的使用示例如下所示:

type ToPath<S extends string> = // 你的实现代码

ToPath<'foo.bar.baz'> //=> ['foo', 'bar', 'baz']
ToPath<'foo[0].bar.baz'> //=> ['foo', '0', 'bar', 'baz']

请在下面评论你的答案。

@sunboyZgz
Copy link

type indexSignature<T> = T extends `${infer H}[${infer M}][${infer R}]`
  ? [H, M, ...indexSignature<`[${R}]`>]
  : T extends `${infer F}[${infer L}]`
  ? [F, L]
  : [T];
type NonSpace<T extends string[]> = T extends [infer H, ...infer R]
  ? R extends string[]
    ? H extends ""
      ? [...NonSpace<R>]
      : [H, ...NonSpace<R>]
    : never
  : T;
type ToPath<S extends string> = S extends `${infer H}.${infer R}`
  ? [...NonSpace<indexSignature<H>>, ...ToPath<R>]
  : NonSpace<indexSignature<S>>;

type t1 = ToPath<"foo.bar.baz">; //=> ['foo', 'bar', 'baz']
type t2 = ToPath<"foo[0][2][3][4].bar[5][6].baz[12][13]">; //=> ['foo','0','2','3','4','bar','5','6','baz','12','13']

@zerolee1231
Copy link

zerolee1231 commented Sep 21, 2021

import { type } from "os";

type ToPath<S extends string> = S  extends `${infer A}.${infer B}` ? [...IndexStructure<A>, ...ToPath<B>] : [...IndexStructure<S>];// 你的实现代码
type IndexStructure<S extends string> = S extends `${infer A}[${infer B}]` ? [A, ...IndexStructure2<`[${B}]`>] : [S]
type IndexStructure2<S extends string> = S extends `[${infer A}][${infer B}]` ? [A, ...IndexStructure2<`[${B}]`>] : S extends `[${infer A}]` ? [A] : [S];

type T1 = ToPath<'foo.bar.baz'> //=> ['foo', 'bar', 'baz']
type T2 = ToPath<'foo[0].bar.baz'> //=> ['foo', '0', 'bar', 'baz']

@zhaoxiongfei
Copy link

type Str2Tuple<S extends string> = S extends `${infer First}[${infer Second}]`
  ? [First, Second]
  : [S];

type ToPath<S extends string> = S extends `${infer First}.${infer Rest}`
  ? [...Str2Tuple<First>, ...ToPath<Rest>]
  : [S];

type T1 = ToPath<"foo.bar.baz">; //=> ['foo', 'bar', 'baz']
type T2 = ToPath<"foo[0].bar.baz">; //=> ['foo', '0', 'bar', 'baz']

@xiaoYuanDun
Copy link

xiaoYuanDun commented Sep 23, 2021

感觉我这个方法有点僵硬, 完全就是字符串的替换, 把 '[' 替换为 '.', ] 替换为 '', 然后检查 '.' 前后的子字符串, 存入结果数组

type ToPath<T extends string, C extends string[] = []> = 
  T extends `${infer R1}[${infer R2}` 
    ? ToPath<`${R1}.${R2}`> 
    : T extends `${infer R3}]${infer R4}` 
      ? ToPath<`${R3}${R4}`> 
      : T  extends `${infer R5}.${infer R6}` 
        ? [R5, ...ToPath<R6, C>] 
        : [T]

//  测试用例
type t1 = ToPath<'foo.bar.baz'> //=> ['foo', 'bar', 'baz']
type t2 = ToPath<'foo[0].bar[1].baz[2].fff'> //=> ['foo', '0', 'bar', 'baz']

@ln0y
Copy link

ln0y commented Sep 26, 2021

  type ToPath<S extends string> =
    S extends '' ? [] :
    S extends `${infer A}[${infer B}]${infer C}` ? [...ToPath<A>, B, ...ToPath<C extends `.${infer D}` ? D : C>] : Split<S, '.'>

  type T1 = ToPath<'foo.bar.baz'> //=> ['foo', 'bar', 'baz']
  type T2 = ToPath<'foo[0].bar.baz'> //=> ['foo', '0', 'bar', 'baz']
  type T3 = ToPath<'foo.bar[0].baz'> //=> ['foo', 'bar', '0', 'baz']
  type T4 = ToPath<'foo.bar.baz[0]'> //=> ['foo', 'bar', 'baz', '0']
  type T5 = ToPath<'baz[0]'> //=> ['baz', '0']
  type T6 = ToPath<'[0].foo[1][3].bar[2]'> //=> ['0','foo','1','3','bar','2']

@Jevon617
Copy link

Jevon617 commented Sep 28, 2021

/**
 * 实现一个 ToPath 工具类型,用于把属性访问(. 或 [])路径转换为元组的形式。具体的使用示例如下所示:
 * 思路, 需要建立两个匹配分支: 
 *    1. 匹配 preCode[0]nextCode
 *    2. 匹配 preCode.nextCode
 * 在匹配到分支1的情况下, preCode 内会存在 可以匹配分支2的情况, 所以需要递归preCode, nextCode也是类似.
 * 同时, 匹配到分支2的情况下, preCode 内会存在 可以匹配分支1的情况, 所以需要递归preCode, nextCode也是类似.
 */

type ToPath<S extends string> = S extends 
    `${infer F}${`[${infer D}]`}${infer R}` 
        ? [...ToPath<F>, ...([D] extends [never] ? [] : [D]), ...ToPath<R>] 
        : S extends `${infer F}.${infer R}` 
            ? [...ToPath<F>, ...ToPath<R>] 
            : S extends '' ? [] : [S]
type P1 = ToPath<'foo.bar.baz'> //=> ['foo', 'bar', 'baz']
type P2 = ToPath<'foo[0].bar.baz'> //=> ['foo', '0', 'bar', 'baz']

@zhaoxiongfei
Copy link

type ToPath<S extends string> = S extends `${infer A}.${infer B}`
  ? [...ToPath<A>, ...ToPath<B>]
  : S extends `${infer A}[${infer B}]`
    ? [A, B]
    : [S]

type T1 = ToPath<'foo.bar.baz'> //=> ['foo', 'bar', 'baz']
type T2 = ToPath<'foo[0].bar.baz'> //=> ['foo', '0', 'bar', 'baz']

利用 infer 的一些小技巧,结合模板变量的用法。

@mingzhans
Copy link

type CC<T extends string> = T extends `${infer H}${'['}${infer G}${']'}` ? [H, G] : [T]
type ToPath<S extends string> = S extends '' ? [] : S extends `${infer A}${'.'}${infer B}` ? [...CC<A>, ...ToPath<B>] : CC<S>// 你的实现代码
type L0 = ToPath<'foo.bar.baz'> //=> ['foo', 'bar', 'baz']
type L1 = ToPath<'foo[0].bar.baz'> //=> ['foo', '0', 'bar', 'baz']
type L2 = ToPath<'foo[0].bar[1].baz'> //=> ['foo', '0', 'bar','1' ,'baz']
type L3 = ToPath<'foo.bar.baz[0]'> //=> ['foo', 'bar', 'baz','0']
type L4 = ToPath<''> //=> ['foo', '0', 'bar', 'baz']

@Gengar-666
Copy link

type ToPath<S extends string> = S extends `${infer A}${"["}${infer C}` 
  ? [A, ...ToPath<C>] 
  : S extends `${infer A}${"]"}${infer C}` 
    ? [A, ...ToPath<C>] 
    : S extends `${infer A}${"."}${infer C}` 
      ? (A extends "" 
        ? [...ToPath<C>] 
        : [A, ...ToPath<C>]) 
      : [S];

type T0 = ToPath<"foo.bar.baz">; //=> ['foo', 'bar', 'baz']
type T1 = ToPath<"foo[0].bar.baz">; //=> ['foo', '0', 'bar', 'baz']

@364
Copy link

364 commented Nov 3, 2021

type StrBrackets<S extends string> = S extends `${infer A}[${infer B}]`
  ? [A, B]
  : [S];

type ToPath<S extends string> = S extends `${infer A}.${infer B}`
  ? [...StrBrackets<A>, ...ToPath<B>]
  : [...StrBrackets<S>];

type toPath = ToPath<"foo.bar.baz">; //=> ['foo', 'bar', 'baz']
type toPath2 = ToPath<"foo[0].bar.baz">; //=> ['foo', '0', 'bar', 'baz']

@xuemanchi
Copy link

xuemanchi commented Nov 4, 2021

type ToPath<S extends string> = S extends `${infer A}[${infer B}]${infer Rest}` ? 
[A, B, ...ToPath<Rest>] :
S extends `${infer C}.${infer D}` ? 
C extends '' ? [...ToPath<D>] :
[C, ...ToPath<D>] :
[S];

type A = ToPath<'foo.bar.baz'> //=> ['foo', 'bar', 'baz']
type B = ToPath<'foo[0].bar.baz'> //=> ['foo', '0', 'bar', 'baz']

@liulise
Copy link

liulise commented Dec 9, 2021

type Split<
S extends string,
Delimiter extends string,
> = S extends `${infer L}${Delimiter}${infer R}`
? [L, ...Split<R, Delimiter>]
: [S];
type ToPath<S extends string, A = Split<S, '.'>> = A extends [infer F, ...infer O]
? F extends `${infer Q}[${infer C}]`
? [Q, C, ...ToPath<'', O>]
: [F, ...ToPath<'', O>]
: A;

type a = ToPath<'foo.bar.baz'>;
type b = ToPath<'foo[0].bar.baz'>

@xuemanchi
Copy link

xuemanchi commented Mar 1, 2022

type ToPath<S extends string, R extends string[] = []> = S extends `${infer Prev}.${infer Last}` ? Prev extends `${infer Key}[${infer Index}]` ? ToPath<Last, [...R, Key, Index]> : ToPath<Last, [...R, Prev]> : '' extends S ? R : [...R, S]; 

 type A = ToPath<'foo.bar.baz'> //=> ['foo', 'bar', 'baz']
 type B = ToPath<'foo[0].bar.baz'> //=> ['foo', '0', 'bar', 'baz']

@zouyk
Copy link

zouyk commented Mar 7, 2022

type ToPath = S extends ${infer A}.${infer B} ? [A, ...ToPath] : [S] // 你的实现代码

type TransferStr<T extends Array = []> = {
[K in keyof T]: T[K] extends [${infer A}]${infer B} ?
[A, B] : T[K] extends ${infer B}[${infer A}] ?
[B, A] : T[K] extends ${infer A}[${infer B}]${infer C} ?
[A, B, C] : T[K]
}
type Flat<T extends Array, Result extends Array = []> =
T extends [infer A, ...infer B] ?
A extends Array ?
Flat<B, [...Result, ...A]> :
Flat<B, [...Result, A]> :
Result

type Result2 = Flat<TransferStr<ToPath<'foo[0].[0]bar.b[0]az'>>> //=> ["foo", "0", "0", "bar", "b", "0", "az"]

@zjxxxxxxxxx
Copy link

type ToPath<S extends string> = S extends `${infer F}.${infer R}`
  ? [...ToPath<F>, ...ToPath<R>]
  : S extends `${infer F}[${infer C}]${infer R}`
  ? [...ToPath<F>, ...ToPath<C>, ...ToPath<R>]
  : S extends ""
  ? []
  : [S];

@heweijian4933
Copy link

heweijian4933 commented Jun 3, 2022

可能是比较简洁好懂的写法了

> 每次看到这种需要循环处理的题目第一反应是想到递归
type ToPath<S extends string> = 
    S extends `${infer First}.${infer Rest}`
    ? First extends `${infer InnerFirst}[${infer Num}]`
        ? [InnerFirst,Num,...ToPath<Rest>]
        : [First,...ToPath<Rest>]
    : [S]

type Res1 = ToPath<'foo.bar.baz'> //=> ['foo', 'bar', 'baz']
type Res2 =ToPath<'foo[0].bar.baz'> //=> ['foo', '0', 'bar', 'baz']

@ChuTingzj
Copy link

//question
// 实现一个 ToPath 工具类型,用于把属性访问(. 或 [])路径转换为元组的形式。具体的使用示例如下所示:
// type ToPath<S extends string> = // 你的实现代码
// ToPath<'foo.bar.baz'> //=> ['foo', 'bar', 'baz']
// ToPath<'foo[0].bar.baz'> //=> ['foo', '0', 'bar', 'baz']

//answer
type ToPath<S extends string> = S extends `${infer T}.${infer R}` ? (T extends `${infer F}[${infer A}]` ? [F, A, ...ToPath<R>] : [T, ...ToPath<R>]) : [S]
type a1 = ToPath<'foo.bar.baz'> //=> ['foo', 'bar', 'baz']
type a2 = ToPath<'foo[0].bar.baz'> //=> ['foo', '0', 'bar', 'baz']

@GuoJianjian
Copy link

type Split<
  S extends string, 
  Delimiter extends string,
> = S extends `${infer F}${Delimiter}${infer Rest}`
  ? [F, ...Split<Rest, Delimiter>]
  : S extends '' ? [] : [S];

type D<S> = S extends `${infer A}[${infer B}]` ? [A, ...Split<B, ']['>] : [S];
type C<T extends any[]> = T extends [infer F, ...infer Rest] ? [...D<F>, ...C<Rest>] : T;
type ToPath<S extends string> = C<Split<S, '.'>>;

type A = ToPath<'foo.bar.baz'> //=> ['foo', 'bar', 'baz']
type B = ToPath<'foo[1].bar[6][7][8].baz[12]'> //=> ["foo", "1", "bar", "6", "7", "8", "baz", "12"]

@hezhisheng1930
Copy link

type ArrayChangeTuple<
S extends string,
TEMP extends string[] = []> = S extends ${infer First}[${infer Center}]${infer Rest}
? First extends ''
? [...TEMP, Center]
: ArrayChangeTuple<Rest, [...TEMP, First, Center]>
: [...TEMP, S];

type ToPath<
S extends string> = S extends ${infer First}.${infer Rest}
? [...ArrayChangeTuple, ...ToPath]
: [S]

@g1f9
Copy link

g1f9 commented Aug 20, 2022

type ToPath<S extends string> = S extends `${infer K}[${infer M}]${infer R2}` ? [K,...ToPath<`${M}${R2}`>] : S extends `${infer P}.${infer Rest}` ? 
                                [P,...ToPath<Rest>] : [S]

type T1 = ToPath<'foo.bar.baz'> //=> ['foo', 'bar', 'baz']
type T2 = ToPath<'foo[0].bar.baz'> //=> ['foo', '0', 'bar', 'baz']

@zhixiaotong
Copy link

zhixiaotong commented Feb 3, 2023

// 拆分
type Split<
	S extends string, 
	Delimiter extends string,
> = S extends `${infer A}${Delimiter}${infer B}` ? [A, ...Split<B, Delimiter>] : [S]

// 将方括号内的类型拆分
type StrSplit<S extends string, R extends string[] = []> = 
S extends `${infer A}[${infer B}]${infer C}` ? (C extends "" ? (A extends "" ? [...R, B]  : [...R, A, B]) : A extends "" ? [...R, B, ...StrSplit<C, R>] : [...R, A, B, ...StrSplit<C, R>]) : [S]

// 拆分数组每一项
type Spliting<T extends string[], R extends string[] = []> = 
  T extends [infer FirstStr extends string, ...infer RestStrs extends string[]] ? 
  (RestStrs extends [] ? [...R, ...StrSplit<FirstStr, R>] : [...R, ...StrSplit<FirstStr, R>, ...Spliting<RestStrs, R>]) : R

type ToPath<S extends string> = Spliting<Split<S, '.'>>


type path1 = ToPath<'foo.bar.baz'> //=> ['foo', 'bar', 'baz']
type path2 = ToPath<'foo[0].bar.baz'> //=> ['foo', '0', 'bar', 'baz']
type path3 = ToPath<'x.b.c[2][2][3].e.f[2][3][4]'> // => ["x", "b", "c", "2", "2", "3", "e", "f", "2", "3", "4"]

@xxiaojiujiu
Copy link

type ToPath<S extends string> = S extends `${infer A}.${infer B}` ? 
  ([...ToPath<A>, ...ToPath<B>]) : 
    (S extends `${infer E}[${infer F}]${infer G}` ? 
      (E extends '' ? (G extends '' ? [F] : [F, ...ToPath<G>]) : (G extends '' ? [E, F] : [E, F, ...ToPath<G>])) : 
        ([S]))
type P1 = ToPath<'foo.bar[0].baz'> //=> ['foo', 'bar', 'baz']
type P2 = ToPath<'foo[0].bar[1].baz'> //=> ['foo', '0', 'bar', 'baz']
type P3 = ToPath<'foo[0]'>
type P4 = ToPath<'foo.bar.baz[0]'>
type P5 = ToPath<'foo.bar.baz'>
type P6 = ToPath<'foo'>
type P7 = ToPath<'foo[0][1][3][4][5].baz.bar[0]'>
type p8 = ToPath<'foo[0].bar'>
type P9 = ToPath<'foo.bar[0]'>
type P10 = ToPath<'foo[0].bar.baz'>
type P11 = ToPath<"foo[0][2][3][4].bar[5][6].baz[12][13]">
type P12 = ToPath<'x.b.c[2][2][3].e.f[2][3][4]'>

@SweeperDuan
Copy link

// 拆分
type Split<
	S extends string, 
	Delimiter extends string,
> = S extends `${infer A}${Delimiter}${infer B}` ? [A, ...Split<B, Delimiter>] : [S]

// 将方括号内的类型拆分
type StrSplit<S extends string, R extends string[] = []> = 
S extends `${infer A}[${infer B}]${infer C}` ? (C extends "" ? (A extends "" ? [...R, B]  : [...R, A, B]) : A extends "" ? [...R, B, ...StrSplit<C, R>] : [...R, A, B, ...StrSplit<C, R>]) : [S]

// 拆分数组每一项
type Spliting<T extends string[], R extends string[] = []> = 
  T extends [infer FirstStr extends string, ...infer RestStrs extends string[]] ? 
  (RestStrs extends [] ? [...R, ...StrSplit<FirstStr, R>] : [...R, ...StrSplit<FirstStr, R>, ...Spliting<RestStrs, R>]) : R

type ToPath<S extends string> = Spliting<Split<S, '.'>>


type path1 = ToPath<'foo.bar.baz'> //=> ['foo', 'bar', 'baz']
type path2 = ToPath<'foo[0].bar.baz'> //=> ['foo', '0', 'bar', 'baz']
type path3 = ToPath<'x.b.c[2][2][3].e.f[2][3][4]'> // => ["x", "b", "c", "2", "2", "3", "e", "f", "2", "3", "4"]

这个是正确的,评论区好多都有问题,遇到这种 casetype T3 = ToPath<'fo[1]o[0].b.ar[2].b[3]a.z.'> 结果就不符合预期了

@lfzs
Copy link

lfzs commented Apr 11, 2024

type StrBrackets<S> = S extends `${infer A}[${infer B}]${infer C}` 
  ? [...(A extends '' ? [] : [A]), B, ...StrBrackets<C>] 
  : (S extends '' ? [] : [S])
type ToPath<S> = S extends `${infer A}.${infer B}` 
  ? [...StrBrackets<A>, ...ToPath<B>] 
  : StrBrackets<S>

type x = ToPath<'foo.bar.baz'> //=> ['foo', 'bar', 'baz']
type y = ToPath<'foo[0].bar.baz'> //=> ['foo', '0', 'bar', 'baz']
type z = ToPath<'foo[0][1].bar.baz'> //=> ['foo', '0', '1', 'bar', 'baz']
type T3 = ToPath<'fo[1]o[0].b.ar[2].b[3]a.z.'> // ["fo", "1", "o", "0", "b", "ar", "2", "b", "3", "a", "z"]
type path3 = ToPath<'x.b.c[2][2][3].e.f[2][3][4]'> // => ["x", "b", "c", "2", "2", "3", "e", "f", "2", "3", "4"]

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests