awesome-typescript icon indicating copy to clipboard operation
awesome-typescript copied to clipboard

「重学TS 2.0 」TS 练习题第六题

Open semlinker opened this issue 4 years ago • 40 comments

第六题

定义一个 NativeFlat 工具类型,支持把数组类型拍平(扁平化)。具体的使用示例如下所示:

type NaiveFlat<T extends any[]> = // 你的实现代码

// 测试用例:
type NaiveResult = NaiveFlat<[['a'], ['b', 'c'], ['d']]>
// NaiveResult的结果: "a" | "b" | "c" | "d"

在完成 NaiveFlat 工具类型之后,在继续实现 DeepFlat 工具类型,以支持多维数组类型:

type DeepFlat<T extends any[]> = unknown // 你的实现代码

// 测试用例
type Deep = [['a'], ['b', 'c'], [['d']], [[[['e']]]]];
type DeepTestResult = DeepFlat<Deep>  
// DeepTestResult: "a" | "b" | "c" | "d" | "e"

请在下面评论你的答案

semlinker avatar Sep 14 '21 15:09 semlinker

目前针对元组内都是一维数组的情况下能够成立,但是如果是多层级的话就不行。比较有局限性。希望宝哥帮忙看一下这种方式是否能够做到通用性。

  • 第一种:
type NaiveFlat<T extends any[]> = T[number] extends any[] ? T[number][number] : T[number]

// 测试用例:
type NaiveResult = NaiveFlat<[['a'], ['b', 'c'], ['d']]> // 'a' | 'b' | 'c' | 'd'
  • 第二种:

type ArrayConcat<T extends any[]> = T extends [infer A, ...infer Rest] ?
    A extends any[] ? [...A, ...ArrayConcat<Rest>] : A : T;

type NativeFlat<T extends any[]> = ArrayConcat<T>[number]

type NativeResult = NativeFlat<[['a'], ['b', 'c'], ['d']]> //  'a' | 'b' | 'c' | 'd'

douhaoi avatar Sep 15 '21 03:09 douhaoi

6.1 NativeFlat

type NaiveFlat<T extends any[]> = {
  [P in keyof T]: T[P] extends any[] ? T[P][number] : T[P]
}[number]

type NaiveResult = NaiveFlat<[['a'], ['b', 'c'], ['d']]>
// NaiveResult的结果: "a" | "b" | "c" | "d"

6.2 DeepFlat

type Deep = [['a'], ['b', 'c'], [['d']], [[[['e']]]]];

type DeepFlat<T extends any[]> = {
  [K in keyof T]: T[K] extends any[] ? DeepFlat<T[K]> : T[K]
}[number]

type DeepTestResult = DeepFlat<Deep>
// DeepTestResult: "a" | "b" | "c" | "d" | "e"

semlinker avatar Sep 16 '21 01:09 semlinker

6.1 NativeFlat

type NaiveFlat<T extends any[]> = T[number] extends infer U // 你的实现代码
  ? U extends any[]
    ? U[number]
    : U
  : never;

// 测试用例:
type NaiveResult = NaiveFlat<[["a"], ["b", "c"], ["d"]]>;
// NaiveResult的结果: "a" | "b" | "c" | "d"

6.2 DeepFlat

type DeepFlat<T extends any[]> = T[number] extends infer U
  ? U extends any[]
    ? DeepFlat<U>
    : U
  : never;

// 测试用例
type Deep = [["a"], ["b", "c"], [["d"]], [[[["e"]]]]];
type DeepTestResult = DeepFlat<Deep>;
// DeepTestResult: "a" | "b" | "c" | "d" | "e"

ccbabi avatar Sep 21 '21 12:09 ccbabi

type NaiveFlat<T extends any[]> = T[number] extends (infer P)[] ? P : T[number];
type NaiveResult = NaiveFlat<[['a'], ['b', 'c'], ['d']]>;
// NaiveResult的结果: "a" | "b" | "c" | "d"

type DeepFlat<T extends any[]> = T[number] extends (infer P)[] ? P extends any[] ? DeepFlat<P> : P : T[number];
type Deep = [['a'], ['b', 'c'], [['d']], [[[['e']]]]];
type DeepTestResult = DeepFlat<Deep>;
// DeepTestResult: "a" | "b" | "c" | "d" | "e"

zsqsmart avatar Sep 22 '21 02:09 zsqsmart

6.1 NativeFlat

type NaiveFlat<T extends any[]> = {
  [P in keyof T]: T[P] extends any[] ? T[P][number] : T[P]
}[number]

type NaiveResult = NaiveFlat<[['a'], ['b', 'c'], ['d']]>
// NaiveResult的结果: "a" | "b" | "c" | "d"

6.2 DeepFlat

type Deep = [['a'], ['b', 'c'], [['d']], [[[['e']]]]];

type DeepFlat<T extends any[]> = {
  [K in keyof T]: T[K] extends any[] ? DeepFlat<T[K]> : T[K]
}[number]

type DeepTestResult = DeepFlat<Deep>
// DeepTestResult: "a" | "b" | "c" | "d" | "e"

DeepFlat最后的[number]的写法有什么说法么?

xwnwho avatar Sep 22 '21 07:09 xwnwho

type NaiveFlat<T extends any[]> = T extends (infer P)[] ? P extends any[] ? NaiveFlat<P> : P : never;
// 测试用例:
type NaiveResult = NaiveFlat<[['a'], ['b', 'c'], ['d']]>;
type DeepResult = NaiveFlat<[['a'], ['b', 'c'], [['d']], [[[['e']]]]]>;

递归写法

jrs64 avatar Sep 22 '21 12:09 jrs64

type NaiveFlat<T extends any[]> = // 你的实现代码

// 测试用例:
type NaiveResult = NaiveFlat<[['a'], ['b', 'c'], ['d']]>
// NaiveResult的结果: "a" | "b" | "c" | "d"
type NaiveFlat<T extends any[]> = T[number] extends { length: number } ? T[number][number] : T[number];

winfa avatar Sep 22 '21 15:09 winfa

type NaiveFlat<T extends any[]> = T extends Array<infer P>
	? P extends any[]
		? NaiveFlat<P>
		: P
	: never

// 测试用例:
type NaiveResult = NaiveFlat<[['a'], ['b', 'c'], ['d']]>
// NaiveResult的结果: "a" | "b" | "c" | "d"
type Deep = [['a'], ['b', 'c'], [['d']], [[[['e']]]]]
type DeepTestResult = NaiveFlat<Deep>
// DeepTestResult的结果: "a" | "b" | "c" | "d" | "e"

overQ-N avatar Sep 23 '21 15:09 overQ-N

type NaiveFlat<T extends any[]> = {
  [P in keyof T]: T[P] extends any[] ? T[P][number] : T[P]
}[number]

type DeepFlat<T extends any[]> = {
  [P in keyof T]: T[P] extends any[] ? DeepFlat<T[P]> : T[P]
}[number]


// 测试用例:
type NaiveResult = NaiveFlat<[['a'], ['b', 'c'], ['d']]>
// NaiveResult的结果: "a" | "b" | "c" | "d"

type DeepTestResult = DeepFlat<[['a'], ['b', ['c']], ['d']]>
// DeepTestResult的结果: "a" | "b" | "c" | "d"

Mrlgm avatar Sep 24 '21 10:09 Mrlgm

type GetArrayEle<T> = {
  [k in keyof T & number]: T[k]
}[keyof T & number]
type TestGetArrayEle = GetArrayEle<[[number, boolean], [[string]]]>
type FlatArray<T> = T extends Array<infer p> ? p : T
type DeepFlatArray<T> = T extends Array<infer p> ? DeepFlatArray<p> : T

type TestFlatArray = FlatArray<TestGetArrayEle>
type TestDeepFlatArray = DeepFlatArray<[['a'], ['b', ['c']], ['d']]>

duriann avatar Sep 29 '21 07:09 duriann

// 定义一个 NativeFlat 工具类型,支持把数组类型拍平(扁平化)。具体的使用示例如下所示:
type NaiveFlat<T extends any[]> = T extends [infer A, ...infer B]
 ? A extends any[]
  ? NaiveFlat<A> | NaiveFlat<B>
  : A | NaiveFlat<B>
 : never;

// 测试用例:
type NaiveResult = NaiveFlat<[['a'], ['b', 'c'], ['d']]>
// NaiveResult的结果: "a" | "b" | "c" | "d"
// 在完成 NaiveFlat 工具类型之后,在继续实现 DeepFlat 工具类型,以支持多维数组类型:

// 测试用例
type Deep = [['a'], ['b', 'c'], [['d']], [[[['e']]]]]
type DeepTestResult = NaiveFlat<Deep>
// DeepTestResult: "a" | "b" | "c" | "d" | "e"

这个题对我来说难度是只有一级的那个扁平化,我这里实现完成后自动就是deep的。 这里使用的知识点也就是 extends 配合 infer 来提取,之后递归的去做。

zhaoxiongfei avatar Oct 01 '21 13:10 zhaoxiongfei

第六题

定义一个 NativeFlat 工具类型,支持把数组类型拍平(扁平化)。具体的使用示例如下所示:

type NaiveFlat<T extends any[]> = // 你的实现代码

// 测试用例:
type NaiveResult = NaiveFlat<[['a'], ['b', 'c'], ['d']]>
// NaiveResult的结果: "a" | "b" | "c" | "d"

在完成 NaiveFlat 工具类型之后,在继续实现 DeepFlat 工具类型,以支持多维数组类型:

type DeepFlat<T extends any[]> = unknown // 你的实现代码

// 测试用例
type Deep = [['a'], ['b', 'c'], [['d']], [[[['e']]]]];
type DeepTestResult = DeepFlat<Deep>  
// DeepTestResult: "a" | "b" | "c" | "d" | "e"

请在下面评论你的答案

题目和示例感觉描述不一致,题目是要求将数组拍平,最终应该还是一个数组类型,但是示例展示的结果却是数组的常量联合类型,类型已经不是数组了,似乎编程获取数组值的类型

yang131323 avatar Oct 29 '21 03:10 yang131323

谁能告诉我一下,这里的 [number] 是做什么用的吗?完全找不到任何文档呀

whatoeat2night avatar Nov 18 '21 00:11 whatoeat2night

[number] 到底是什么意思啊

rookiecdn avatar Nov 18 '21 05:11 rookiecdn

type NaiveFlat<T extends any[]> = { [K in keyof T]: T[K] extends any[] ? T[K][number] : T[K] }[number]

// 测试用例: type NaiveResult = NaiveFlat<[["a"], ["b", "c"], ["d"]]>; // NaiveResult的结果: "a" | "b" | "c" | "d"

type DeepFlat<T extends any[]> = { [K in keyof T]: T[K] extends any[] ? NaiveFlat<T[K]> : T[K] }[number]

// 测试用例 type Deep = [['a'], ['b', 'c'], [['d']], [[[['e']]]]]; type DeepTestResult = DeepFlat<Deep>

// 通用解法 // type NaiveFlat<T extends any[]> = T extends [infer A, ...infer B] // ? A extends any[] // ? NaiveFlat<A> | NaiveFlat<B> // : A | NaiveFlat<B> // : never;

yanglinxiao avatar Nov 19 '21 02:11 yanglinxiao

type NaiveFlat<T extends any[]> = T extends Array<infer R> ? (R extends any[] ? NaiveFlat<R> : R) : never;

liulise avatar Dec 06 '21 08:12 liulise

为什么加[number],有大佬知道,踢我一下

changeling123xu avatar Dec 07 '21 08:12 changeling123xu

["Q","W"][number] {0:"Q",1:"W",}[number]这种格式为什么会自动循环展开取值啊,学TS的时候好像没看到这种写法啊

hu0115 avatar Dec 09 '21 03:12 hu0115

如果固定双层数组的话,用这个试试

type NaiveFlat<T extends any[]> = T[number][number]

多层实现方法,适用任意层级,同样可以替换上面的NaiveFlat

type DeepFlat<T> = T extends any[] ? DeepFlat<T[number]> : T

ts@ 4.2.3

dolphin0618 avatar Dec 10 '21 08:12 dolphin0618

["Q","W"][number] {0:"Q",1:"W",}[number]这种格式为什么会自动循环展开取值啊,学TS的时候好像没看到这种写法啊

["Q","W"][0] // Q
["Q","W"][1 | 2]  // Q | W
//  1 | 2 extends number
["Q","W"][number]  // Q | W

dolphin0618 avatar Dec 10 '21 15:12 dolphin0618

为啥这样无法递归取到内部的type啊? type DeepFlat<Arr extends any[]> = Arr[number] extends any[] ? DeepFlat<Arr[number]> : Arr[number];

wildes2021 avatar Dec 23 '21 08:12 wildes2021

["Q","W"][0 | 1] // Q | W

ihoneys avatar Jan 13 '22 07:01 ihoneys

type DeepFlat<T extends any[]> = T extends Array<infer R> ? (R extends any[] ? DeepFlat<R> : R) : T
type Deep = [['a'], ['b', 'c'], [['d']], [[[['e']]]]]
type DeepTestResult = DeepFlat<Deep>

jeffacode avatar Feb 09 '22 07:02 jeffacode

type NaiveFlat<T extends any[]> = T extends [infer F, ...infer R]
  ? (F extends unknown[] ? NaiveFlat<F> : F) | NaiveFlat<R>
  : T extends []
  ? never
  : T;

zjxxxxxxxxx avatar Mar 23 '22 06:03 zjxxxxxxxxx

一个月能告诉我一下,这里的 [number] 是什么用的吗?完全找不到文档呀

[number] 用来代指所有数组下标,不管下标 0 还是下标 1,它们都是 number 型。 [''a,'b'][number] === ['a','b'][0|1] === 'a'|'b'

zjxxxxxxxxx avatar Mar 23 '22 06:03 zjxxxxxxxxx

目前针对元组内都是一维数组的情况下能够成立,但是如果是多层级的话就不行。比较有局限性。希望宝哥帮忙看一下这种方式是否能够做到通用性。

  • 第一种:
type NaiveFlat<T extends any[]> = T[number] extends any[] ? T[number][number] : T[number]

// 测试用例:
type NaiveResult = NaiveFlat<[['a'], ['b', 'c'], ['d']]> // 'a' | 'b' | 'c' | 'd'
  • 第二种:
type ArrayConcat<T extends any[]> = T extends [infer A, ...infer Rest] ?
    A extends any[] ? [...A, ...ArrayConcat<Rest>] : A : T;

type NativeFlat<T extends any[]> = ArrayConcat<T>[number]

type NativeResult = NativeFlat<[['a'], ['b', 'c'], ['d']]> //  'a' | 'b' | 'c' | 'd'

可以 : type NaiveFlat<T extends any[]> =T[number] extends (infer P)[] ? P extends any[] ? NaiveFlat<P> : P : T[number]

Bo-Teng avatar May 11 '22 15:05 Bo-Teng

为啥这样无法递归取到内部的type啊? type DeepFlat<Arr extends any[]> = Arr[number] extends any[] ? DeepFlat<Arr[number]> : Arr[number];

同问,为啥少包一层条件语句就不行了呢

shanbinbin avatar May 17 '22 03:05 shanbinbin

type Flat<T extends any[]> = {
    // 递归调用
    [P in keyof T]: T[P] extends any[] ? DeepFlat<T[P]> : T[P] 
}

// 测试用例
type Deep = [['a'], ['b', 'c'], [['d']], [[[['e']]]]];
type DeepTestResult = Flat<Deep>  
type NaiveResult = Flat<[['a'], ['b', 'c'], ['d']]>
// NaiveResult的结果: "a" | "b" | "c" | "d"
// DeepTestResult: "a" | "b" | "c" | "d" | "e"

YJCCreateAHistory avatar May 24 '22 11:05 YJCCreateAHistory

type DeepFlat<T> = T extends Array<infer U> ? DeepFlat<U> : T;

// 测试用例:
type NaiveResult = DeepFlat<[["a"], [["b"], "c"], ["d"]]>;

githuandong avatar May 25 '22 08:05 githuandong

// 解法1: 最佳解法, 通过inter来推断一个P类型
// 如果P类型扩展与any[], 也就证明它是数组, 这个时候递归来执行NaiveFlat
// 否则, 直接返回此类型
// 如果T不扩展于 any[] (这里是(infer P)[], 额外加了个类型的推断) 则为never
type NaiveFlat<T extends any[]> = T extends (infer P)[] ? P extends any[] ? NaiveFlat<P> : P : never

// 解法2
// 解法2之前, 我们先了解一个前置知识, 如何提取数组的值, 作为类型
type TypeD = ['a', 'b']
// 这里的原因是: 使用[number]相当于提取了所有的数组下标, 通过数组下标则可以取到所有的数组值了
type TypeKeyD = TypeD[number] // 'a' | 'b'
// 因此, 解法2到这里就非常简单了, 只需要判断一下, 如果是数组, 则继续往下递归执行, 否则返回该值即可
type NaiveFlat1<T extends any[]> = {
  [P in keyof T]: T[P] extends any[] ? NaiveFlat1<T[P]> : T[P]
}[number]

ChangerHe avatar May 26 '22 16:05 ChangerHe