Comments (39)
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"
from awesome-typescript.
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']]]]]>;
递归写法
from awesome-typescript.
["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
from awesome-typescript.
// 解法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]
from awesome-typescript.
一个月能告诉我一下,这里的 [number] 是什么用的吗?完全找不到文档呀
[number] 用来代指所有数组下标,不管下标 0 还是下标 1,它们都是 number 型。
[''a,'b'][number] === ['a','b'][0|1] === 'a'|'b'
from awesome-typescript.
// 定义一个 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 来提取,之后递归的去做。
from awesome-typescript.
如果固定双层数组的话,用这个试试
type NaiveFlat<T extends any[]> = T[number][number]
多层实现方法,适用任意层级,同样可以替换上面的NaiveFlat
type DeepFlat<T> = T extends any[] ? DeepFlat<T[number]> : T
ts@ 4.2.3
from awesome-typescript.
目前针对元组内都是一维数组的情况下能够成立,但是如果是多层级的话就不行。比较有局限性。希望宝哥帮忙看一下这种方式是否能够做到通用性。
- 第一种:
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'
from awesome-typescript.
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"
from awesome-typescript.
type DeepFlat<T> = T extends Array<infer U> ? DeepFlat<U> : T;
// 测试用例:
type NaiveResult = DeepFlat<[["a"], [["b"], "c"], ["d"]]>;
from awesome-typescript.
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"
from awesome-typescript.
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]的写法有什么说法么?
from awesome-typescript.
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];
from awesome-typescript.
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"
from awesome-typescript.
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"
from awesome-typescript.
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']]>
from awesome-typescript.
第六题
定义一个 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"请在下面评论你的答案
题目和示例感觉描述不一致,题目是要求将数组拍平,最终应该还是一个数组类型,但是示例展示的结果却是数组的常量联合类型,类型已经不是数组了,似乎编程获取数组值的类型
from awesome-typescript.
谁能告诉我一下,这里的 [number] 是做什么用的吗?完全找不到任何文档呀
from awesome-typescript.
[number] 到底是什么意思啊
from awesome-typescript.
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
// 通用解法
// type NaiveFlat<T extends any[]> = T extends [infer A, ...infer B]
// ? A extends any[]
// ? NaiveFlat | NaiveFlat
// : A | NaiveFlat
// : never;
from awesome-typescript.
type NaiveFlat<T extends any[]> = T extends Array<infer R> ? (R extends any[] ? NaiveFlat<R> : R) : never;
from awesome-typescript.
为什么加[number],有大佬知道,踢我一下
from awesome-typescript.
["Q","W"][number] {0:"Q",1:"W",}[number]这种格式为什么会自动循环展开取值啊,学TS的时候好像没看到这种写法啊
from awesome-typescript.
为啥这样无法递归取到内部的type啊?
type DeepFlat<Arr extends any[]> = Arr[number] extends any[] ? DeepFlat<Arr[number]> : Arr[number];
from awesome-typescript.
["Q","W"][0 | 1] // Q | W
from awesome-typescript.
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>
from awesome-typescript.
type NaiveFlat<T extends any[]> = T extends [infer F, ...infer R]
? (F extends unknown[] ? NaiveFlat<F> : F) | NaiveFlat<R>
: T extends []
? never
: T;
from awesome-typescript.
目前针对元组内都是一维数组的情况下能够成立,但是如果是多层级的话就不行。比较有局限性。希望宝哥帮忙看一下这种方式是否能够做到通用性。
- 第一种:
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 : T[number]
from awesome-typescript.
为啥这样无法递归取到内部的type啊? type DeepFlat<Arr extends any[]> = Arr[number] extends any[] ? DeepFlat<Arr[number]> : Arr[number];
同问,为啥少包一层条件语句就不行了呢
from awesome-typescript.
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"
from awesome-typescript.
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"
@nilzhao 但是如果增加一个 'e'
type NaiveResult = NaiveFlat<[['a'], ['b', 'c'], ['d'],'e']>
// 类型为: '["a"] | ["b", "c"] | ["d"] | "e"'. 而不是 "a" | "b" | "c" | "d" | "e"
总算看出问题,因为T是二维数组,T[number]代码T里的每个元素,而'e'是string,所以T[number]不能表示T中元素的所有类型,即不满足类型定义,全部都是false.
from awesome-typescript.
number 是什么虎狼用法?有相关文档吗?
from awesome-typescript.
关于T[number] 为什么可以这样用 在ts 索引类型访问中可以找到答案
from awesome-typescript.
// 二维拍平
type NaiveFlat<T extends any[]> = T[number] extends (infer P)[] ? P : T[number]
// 深度拍平
type DeepFlat<T> = T extends (infer P)[] ? DeepFlat<P> : T
// 测试
type AAA = NaiveFlat<[['a'], ['b', 'c'], ['d']]>
// "a" | "b" | "c" | "d"
type BBB = DeepFlat<[['a'], ['b', 'c'], ['d', ['e', 'f', ['G']]]]>
// "a" | "b" | "c" | "d" | "e" | "f" | "G"
from awesome-typescript.
// 递归
type DeepFlat<T extends unknown[]> = T extends [infer F, ...infer Rest]
? F extends unknown[]
? DeepFlat<F> | DeepFlat<Rest>
: F | DeepFlat<Rest>
: never
type DeepTestResult1 = DeepFlat<[['a', [[[['e']]]], 'be', 'fsdfg'], ['b', 'c'], ['d']]>
// "e" | "a" | "be" | "fsdfg" | "b" | "c" | "d"
type DeepTestResult2 = DeepFlat<[['a'], ['b', 'c'], [['d']], [[[['e']]]]]>
// "e" | "a" | "b" | "c" | "d"
from awesome-typescript.
对于第一种,上面的几种方法有些问题
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 ErrorResult = NaiveFlat<[['a'], ['b', 'c'], ['d'], 'f']> // ["a"] | ["b", "c"] | ["d"] | "f"
还有后面的另一种
type NaiveFlat<T extends any[]> = T[number] extends (infer P)[] ? P : T[number]
// 使用上述两个测试用例
type NaiveResult = NaiveFlat<[['a'], ['b', 'c'], ['d']]> // 'a' | 'b' | 'c' | 'd'
type ErrorResult = NaiveFlat<[['a'], ['b', 'c'], ['d'], 'f']> // ["a"] | ["b", "c"] | ["d"] | "f"
TS的一些默认行为真是让人摸不着头脑啊
然后还有一个问题,对于第二种
type DeepFlat<Arr extends any[]> = Arr[number] extends any[] ? DeepFlat<Arr[number]> : Arr[number];
// 测试用例
type Deep = [ ['a'], ['b', 'c'], [['d']], [[[['e']]]], 'f'];
type DeepTestResult = DeepFlat<Deep> // ["a"] | ["b", "c"] | "f" | [["d"]] | [[[["e"]]]]
这显然是一个比较符合直觉的递归写法,但是结果却不正确
所以我大胆猜测一手,是在条件判断语句内使用**Arr[number]**引起的!
浅浅的验证下
第一种:
type NaiveFlat<T extends any[], V = T[number]> = V extends any[] ? V[number] : V;
// 使用上述两个测试用例
type NaiveResult = NaiveFlat<[['a'], ['b', 'c'], ['d']]> // 'a' | 'b' | 'c' | 'd'
type ErrorResult = NaiveFlat<[['a'], ['b', 'c'], ['d'], 'f']> // "a" | "b" | "c" | "d" | "f"
第二种:
type DeepFlat<T extends any[], V = T[number]> = V extends any[] ? DeepFlat<V> : V;
// 测试用例
type Deep = [ ['a'], ['b', 'c'], [['d']], [[[['e']]]], 'f'];
type DeepTestResult = DeepFlat<Deep> // "a" | "b" | "c" | "d" | "f" | "e"
虽然Arr[number]和泛型V都代表了联合类型,但执行结果却截然不同
有大佬弄清楚原理请记得踢我
from awesome-typescript.
// type NaiveFlat<T extends any[]> = {
// [K in keyof T]:T[K] extends any[]?T[K][number]:T[K]
// }
//上述类型测试用例结果为["a", "b" | "c", "d", "e"],所以需要加[number]展开
type NaiveFlat<T extends any[]> = {
[K in keyof T]:T[K] extends any[]?T[K][number]:T[K]
}[number]
type DeepFlat<T extends any[]> = {
[K in keyof T]:T[K] extends any[]?DeepFlat<T[K]>:T[K]
}[number]
// 测试用例:
type NaiveResult = NaiveFlat<[['a'], ['b', 'c'], ['d'],'e']>
//type NaiveResult = "a" | "b" | "c" | "d" | "e"
type DeepResult = DeepFlat<['a',['b','c'],['d'],[['e','f']],[[[['g']]]]]>
// type DeepResult = "a" | "b" | "c" | "d" | "e" | "f" | "g"
from awesome-typescript.
type NaiveFlat<T extends any[]> = {
[K in keyof T]: T[K] extends any[] ? T[K][number] : T[K]
}[number]
type DeepFlat<T extends any[]> = {
[K in keyof T]: T[K] extends any[] ? DeepFlat<T[K]> : T[K]
}[number]
from awesome-typescript.
type NaiveFlat = T extends Array ? NaiveFlat : T // 你的实现代码
// 测试用例:
type NaiveResult = NaiveFlat<[['a'], ['b', 'c'], ['d']]>
// 测试用例
type Deep = [['a'], ['b', 'c'], [['d']], [[[['e']]]]]
type DeepTestResult = NaiveFlat
from awesome-typescript.
Related Issues (20)
- typescript练习第二题
- 报错的原因是返回值类型不匹配,返回值的类型是User,但T比User的范围更大
- ...
- #### 7.1 EmptyObject
- 「重学TS 2.0 」TS 练习题第四十一题 HOT 9
- 「重学TS 2.0 」TS 练习题第四十二题 HOT 12
- 「重学TS 2.0 」TS 练习题第四十三题 HOT 10
- 「重学TS 2.0 」TS 练习题第四十四题 HOT 4
- 「重学TS 2.0 」TS 练习题第四十五题 HOT 4
- 「重学TS 2.0 」TS 练习题第四十六题 HOT 5
- 「重学TS 2.0 」TS 练习题第四十七题 HOT 7
- 「重学TS 2.0 」TS 练习题第四十八题 HOT 4
- readme里的电子书下载地址403了 HOT 2
- 疑惑返回类型加Partial为什么不行 HOT 1
- 第一题
- 收藏学习!!!
- 抱歉,点击错了
- 「重学TS 2.0 」TS 练习题第四十九题 HOT 4
- > ```ts
- 练习第一题 HOT 1
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from awesome-typescript.