来做一个好玩的猜数字游戏吧。
看一下游戏规则。
通常由两个人玩,一方出数字,一方猜。出数字的人要想好一个没有重复数字的4个数,不能让猜的人知道。猜的人就可以开始猜。每猜一个数字,出数者就要根据这个数字给出几A几B,其中A前面的数字表示位置正确的数的个数,而B前的数字表示数字正确而位置不对的数的个数。
如正确答案为 5234,而猜的人猜 5346,则是 1A2B,其中有一个5的位置对了,记为1A,而3和4这两个数字对了,而位置没对,因此记为 2B,合起来就是 1A2B。
js 写猜数字好写,就是2个循环,那ts中怎么实现呢
extentds
extends 可以判断出 A 类型 是否是 B 类型的子类,对于 字符串,数字类型就相当于判断值相等
解构 infer
在`${infer A}${infer B}`
中 infer 相当于将结构的字符串值赋给一个类型 A 和 B ,递归一下就有了获取每一位的字符串的能力
范型递归
可以用 extends 作为终止条件,递归的调用类型,在递归中加入参数的传递,最后可以输出一个元祖类型当作结果
type Fn<Arr extends 1[] = []> = Arr['length'] extends 5
? Fn<[...Arr, 1]>
: '结束'
ts猜数字的实现
// +1
type Aplus1<n extends number, arr extends 1[] = []> = n extends arr['length']
? [...arr, 1]['length']
: Aplus1<n, [...arr, 1]>
type Each<char extends string, S extends string, charIndex extends number, index extends number = 0, A extends 0 | 1 = 0, B extends 0 | 1 = 1> =
S extends `${infer P}${infer Q}`
? char extends P
? charIndex extends index // 不算
? [1, 0]
// @ts-ignore
: Each<char, Q, charIndex, Aplus1<index>, 0, 1>
// @ts-ignore
: Each<char, Q, charIndex, Aplus1<index>, A, B>
: [A, B]
type Main<S1 extends string, S2 extends string, index extends number = 0, A extends 1[] = [], B extends 1[] = []> =
S1 extends `${infer P}${infer Q}`
? Each<P, S2, index> extends [infer CA, infer CB]
? Main<Q, S2, Aplus1<index>, CA extends 0 ? A : [...A, 1], CB extends 0 ? B : [...B, 1]>
: never
: [`A:${A['length']}`, `B:${B['length']}`]
type Questen1<T extends string> = Main<T, 'zengpengshabi'>