「重学TS 2.0 」TS 练习题第六题
第六题
定义一个 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"
请在下面评论你的答案
目前针对元组内都是一维数组的情况下能够成立,但是如果是多层级的话就不行。比较有局限性。希望宝哥帮忙看一下这种方式是否能够做到通用性。
- 第一种:
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'
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"
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"
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"
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]的写法有什么说法么?
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']]]]]>;
递归写法
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];
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"
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"
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']]>
// 定义一个 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 来提取,之后递归的去做。
第六题
定义一个 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"请在下面评论你的答案
题目和示例感觉描述不一致,题目是要求将数组拍平,最终应该还是一个数组类型,但是示例展示的结果却是数组的常量联合类型,类型已经不是数组了,似乎编程获取数组值的类型
谁能告诉我一下,这里的 [number] 是做什么用的吗?完全找不到任何文档呀
[number] 到底是什么意思啊
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;
type NaiveFlat<T extends any[]> = T extends Array<infer R> ? (R extends any[] ? NaiveFlat<R> : R) : never;
为什么加[number],有大佬知道,踢我一下
["Q","W"][number] {0:"Q",1:"W",}[number]这种格式为什么会自动循环展开取值啊,学TS的时候好像没看到这种写法啊
如果固定双层数组的话,用这个试试
type NaiveFlat<T extends any[]> = T[number][number]
多层实现方法,适用任意层级,同样可以替换上面的NaiveFlat
type DeepFlat<T> = T extends any[] ? DeepFlat<T[number]> : T
ts@ 4.2.3
["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
为啥这样无法递归取到内部的type啊? type DeepFlat<Arr extends any[]> = Arr[number] extends any[] ? DeepFlat<Arr[number]> : Arr[number];
["Q","W"][0 | 1] // Q | W
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>
type NaiveFlat<T extends any[]> = T extends [infer F, ...infer R]
? (F extends unknown[] ? NaiveFlat<F> : F) | NaiveFlat<R>
: T extends []
? never
: T;
一个月能告诉我一下,这里的 [number] 是什么用的吗?完全找不到文档呀
[number] 用来代指所有数组下标,不管下标 0 还是下标 1,它们都是 number 型。 [''a,'b'][number] === ['a','b'][0|1] === 'a'|'b'
目前针对元组内都是一维数组的情况下能够成立,但是如果是多层级的话就不行。比较有局限性。希望宝哥帮忙看一下这种方式是否能够做到通用性。
- 第一种:
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]
为啥这样无法递归取到内部的type啊? type DeepFlat<Arr extends any[]> = Arr[number] extends any[] ? DeepFlat<Arr[number]> : Arr[number];
同问,为啥少包一层条件语句就不行了呢
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"
type DeepFlat<T> = T extends Array<infer U> ? DeepFlat<U> : T;
// 测试用例:
type NaiveResult = DeepFlat<[["a"], [["b"], "c"], ["d"]]>;
// 解法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]