// your answers
After learning from the existing solutions, I found no answer of this challenge for me, cause I think it's not a good challenge. Though there are good points to learn:
What's the flaws of this challenge IMO?
as
to cast the index, which is not safe for useri
is used in a for-loop with statements like i < ...
and i++
, i
must be a number, not a symbol or other type, so the solution choose to(has to) make it a more concrete number. but this is a leak of abstraction, no matter how magic/secrete the concrete number is, it is a concrete number, so user may find it in editor, just write the raw number instead of i
to mock the index, and other code may treat the i
as the concrete number and somehow breaks other aggreetments. In a word, it's not good to use a concrete number to replace the original number
type.Thanks for this challenge and the points learned from it.
Solution by zhaoyao91 #23450
type Secrets = [
1e32,2e32,3e32,4e32,5e32,6e32,7e32,8e32,9e32,10e32,
11e32,12e32,13e32,14e32,15e32,16e32,17e32,18e32,19e32,20e32,
21e32,22e32,23e32,24e32,25e32,26e32,27e32,28e32,29e32,30e32,
31e32,32e32,33e32,34e32,35e32,36e32,37e32,38e32,39e32,40e32,
41e32,42e32,43e32,44e32,45e32,46e32,47e32,48e32,49e32,50e32,
51e32,52e32,53e32,54e32,55e32,56e32,57e32,58e32,59e32,60e32,
61e32,62e32,63e32,64e32,65e32,66e32,67e32,68e32,69e32,70e32,
71e32,72e32,73e32,74e32,75e32,76e32,77e32,78e32,79e32,80e32,
81e32,82e32,83e32,84e32,85e32,86e32,87e32,88e32,89e32,90e32,
91e32,92e32,93e32,94e32,95e32,96e32,97e32,98e32,99e32,100e32,
101e32,102e32,103e32,104e32,105e32,106e32,107e32,108e32,109e32,110e32,
111e32,112e32,113e32,114e32,115e32,116e32,117e32,118e32,119e32,120e32,
121e32,122e32,123e32,124e32,125e32,126e32,127e32,128e32,129e32,130e32,
131e32,132e32,133e32,134e32,135e32,136e32,137e32,138e32,139e32,140e32,
141e32,142e32,143e32,144e32,145e32,146e32,147e32,148e32,149e32,150e32,
151e32,152e32,153e32,154e32,155e32,156e32,157e32,158e32,159e32,160e32,
161e32,162e32,163e32,164e32,165e32,166e32,167e32,168e32,169e32,170e32,
171e32,172e32,173e32,174e32,175e32,176e32,177e32,178e32,179e32,180e32,
181e32,182e32,183e32,184e32,185e32,186e32,187e32,188e32,189e32,190e32,
191e32,192e32,193e32,194e32,195e32,196e32,197e32,198e32,199e32,200e32
]
type UniqIndex<S> = ToSecretsUion<BitString<S>>
type ToSecretsUion<BS, SS=Secrets, ACC=never>
= SS extends [infer S0, infer S1, ...infer TS]
? BS extends `0${infer R}` ? ToSecretsUion<R, TS, ACC | S0>
: BS extends `1${infer R}` ? ToSecretsUion<R, TS, ACC | S1>
: ACC
: never
type BitString<S, ACC extends string = ''>
= S extends `${infer L}${infer R}` ? BitString<R, `${ACC}${CharToBS[keyof CharToBS & L]}`> : ACC
type CharToBS
= CharToBS_Helper<"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_$">
type CharToBS_Helper<CS, BS='0000000', ACC={}>
= CS extends `${infer L}${infer R}`? CharToBS_Helper<R, AddBit<BS>, ACC & Record<L, BS>> : ACC
type AddBit<S>
= S extends `${infer R}1` ? `${AddBit<R>}0` : S extends `${infer U}0` ? `${U}1` : never
function assertArrayIndex<A extends readonly any[], K extends string>(
array: IsTuple<A> extends true ? never : A,
key: K) : asserts array is typeof array & Record<'key', UniqIndex<K>> & Record<UniqIndex<K>, A[number]> {}
type IsTuple<T extends readonly unknown[]> = number extends T['length'] ? false : true
type Index<A> = A[keyof A & 'key']
Solution by okayu29 #17791
// 构造数组
type BuildArray<N extends number, A extends unknown[] = []> = A['length'] extends N ? A : BuildArray<N, [...A, unknown]>
// 映射字母,用于计算字符串的hash值
type HashMap = {
a: BuildArray<1>
b: BuildArray<2>
c: BuildArray<3>
d: BuildArray<4>
e: BuildArray<5>
f: BuildArray<6>
g: BuildArray<7>
h: BuildArray<8>
i: BuildArray<9>
j: BuildArray<10>
k: BuildArray<11>
l: BuildArray<12>
m: BuildArray<13>
n: BuildArray<14>
o: BuildArray<15>
p: BuildArray<16>
q: BuildArray<17>
r: BuildArray<18>
s: BuildArray<19>
t: BuildArray<20>
u: BuildArray<21>
v: BuildArray<22>
w: BuildArray<23>
x: BuildArray<24>
y: BuildArray<25>
z: BuildArray<26>
}
// 将哈希字符串转为哈希值
type Hash<HashString extends string, HashArray extends unknown[] = []> = HashString extends `${infer F extends keyof HashMap}${infer rest}`
? Hash<rest, [...HashArray, ...HashMap[F]]>
: HashArray['length']
// 当HashString不为空时,依次判断每个字符是否符合HashMap的key值
type IsHashKeyHelper<HashString extends string> = HashString extends `${infer F}${infer rest}`
? F extends keyof HashMap
? IsHashKeyHelper<rest>
: false
: true
// 当HashString为空时,返回false
type IsHashKey<HashString extends string> = HashString extends '' ? false : IsHashKeyHelper<HashString>
declare const KEY: unique symbol
// 给数组 A 的类型挂载一个唯一的哈希值symbol => hashKey,以及哈希值对应的数组元素类型,hashKey => A[number]
function assertArrayIndex<A extends readonly unknown[], HashString extends string>(
array: number extends A['length'] ? A : never, // 判断 A 是否是只读元组,是的话 A['length'] 会返回具体数字,则 array: never
hashString: IsHashKey<HashString> extends true ? HashString : never, // 判断 hashString 是否是有效的哈希字符串
): asserts array is (number extends A['length'] // 如果 A 是只读元组, 则断言 array 为 never 类型
? A &
{ readonly [KEY]: Hash<HashString> } & // 暂存 A 的哈希值, 在 Index 工具函数中取出
{ readonly [hashString in Hash<HashString>]: A[number] } // 访问 A[Index],若 Index 为 hashKey, 则能正确访问
: never)
{} // 函数体
// 取出Array的哈希值,作为遍历的索引变量的类型,这样后续访问 A[Index]
type Index<Array extends { readonly [KEY]: number }> = Array[typeof KEY]
Solution by wzp-coding #17338
// your answers
type Dictionary =
{
'a':'1','b':'2','c':'3','d':'4','e':'5','f':'6','g':'7','h':'8','i':'9','j':'10',
'k':'11','l':'12','m':'13','n':'14','o':'15','p':'16','q':'17','r':'18','s':'19',
't':'20','u':'21','v':'22','w':'23','x':'24','y':'25','z':'26', 'A':'27','B':'28',
'C':'29','D':'30','E':'31','F':'32','G':'33','H':'34','I':'35','J':'36','K':'37',
'L':'38','M':'39','N':'40','O':'41','P':'42','Q':'43','R':'44','S':'45','T':'46',
'U':'47','V':'48','W':'49','X':'50','Y':'51','Z':'52', '1':'53','2':'54','3':'55',
'4':'56','5':'57','6':'58','7':'59','8':'60','9':'61'} ;
type Digits =
{
'0':[],
'1':[0],
'2':[0,0],
'3':[0,0,0],
'4':[0,0,0,0],
'5':[0,0,0,0,0],
'6':[0,0,0,0,0,0],
'7':[0,0,0,0,0,0,0],
'8':[0,0,0,0,0,0,0,0],
'9':[0,0,0,0,0,0,0,0,0] ;
} ;
type UnPack<
S extends string> =
S extends `${infer R extends keyof Digits}${infer U extends string}`
? [...Digits[R],...UnPack<U>]
: [] ;
type Hash<
Input extends string,
Increment extends readonly any[]=[],
Container extends readonly any[]=[],
> =
Input extends `${infer R extends keyof Dictionary}${infer U extends string}`
? Hash<U,[...Increment,R],[...Container,...UnPack<`${Dictionary[R]}${Increment['length']}`>]>
: Container['length'] ;
declare function assertArrayIndex<
A extends readonly any[],
Key extends string,
>(arr: number extends A['length'] ? A : never, key: Key):
asserts arr is (typeof arr)&{[J in Hash<Key>|'key'] : J extends 'key' ? Hash<Key> :A[number]} ;
type Index<
T extends readonly any[]> =
T['key'&keyof T] ;
Solution by justBadProgrammer #16981
type HashMap = {a: 11, b: 12, c: 13, d: 14, e: 15, f: 16, g: 17, h: 18, i: 19, j: 20, k: 21, l: 22, m: 23, n: 24, o: 25, p: 26, q: 27, r: 28, s: 29, t: 30, u: 31, v: 32, w: 33, x: 34, y: 35, z: 36}
type Hash<S, Num extends string = '2'> =
S extends `${infer First extends string}${infer Trail extends string}`
? Lowercase<First> extends keyof HashMap
? Hash<Trail, `${Num}${HashMap[Lowercase<First>]}`>
: '00'
: Num
function assertArrayIndex<A extends readonly any[], K extends string>(
array: number extends A['length'] ? A : never,
key: K
): asserts array is (
number extends A['length']
? A &
{[P in -1 | ToNum<`-${Hash<K>}`>]:
P extends -1
? ToNum<`-${Hash<K>}`>
: A[number]
}
: never
) {}
type ToNum<S extends string> =
S extends `${infer N extends number}`
? number extends N
? never
: N
: never
type Index<A> = -1 extends keyof A ? A[-1] : number
Solution by teamchong #11642
// your answers
type HashMapHelper<T extends number, R extends unknown[] = []> = R['length'] extends T
? R
: HashMapHelper<T, [...R, unknown]>
type HashMap = {
'0': HashMapHelper<0>
'1': HashMapHelper<1>
'2': HashMapHelper<2>
'3': HashMapHelper<3>
'4': HashMapHelper<4>
'5': HashMapHelper<5>
'6': HashMapHelper<6>
'7': HashMapHelper<7>
'8': HashMapHelper<8>
'9': HashMapHelper<9>
a: HashMapHelper<1>
b: HashMapHelper<2>
c: HashMapHelper<3>
d: HashMapHelper<4>
e: HashMapHelper<5>
f: HashMapHelper<6>
g: HashMapHelper<7>
h: HashMapHelper<8>
i: HashMapHelper<9>
j: HashMapHelper<10>
k: HashMapHelper<11>
l: HashMapHelper<12>
m: HashMapHelper<13>
n: HashMapHelper<14>
o: HashMapHelper<15>
p: HashMapHelper<16>
q: HashMapHelper<17>
r: HashMapHelper<18>
s: HashMapHelper<19>
t: HashMapHelper<20>
u: HashMapHelper<21>
v: HashMapHelper<22>
w: HashMapHelper<23>
x: HashMapHelper<24>
y: HashMapHelper<25>
z: HashMapHelper<26>
}
type Hash<T extends string, RR extends unknown[] = []> = T extends `${infer L}${infer R}`
? Hash<R, [...RR, ...HashMap[keyof HashMap & L]]>
: RR['length']
type IsKeyHelper<K extends string> = K extends `${infer L}${infer R}`
? L extends keyof HashMap
? IsKeyHelper<R>
: false
: true
type IsKey<K extends string> = K extends '' ? false : IsKeyHelper<K>
declare const KEY: unique symbol
function assertArrayIndex<A extends readonly unknown[], K extends string>(
array: number extends A['length'] ? A : never,
key: IsKey<K> extends true ? K : never,
): asserts array is number extends A['length']
? A & { readonly [KEY]: Hash<K> } & {
readonly [key in Hash<K>]: A[number]
}
: never {}
type Index<Array extends { readonly [KEY]: number }> = Array[typeof KEY]
Solution by ZangYuSong #7058
type Ord
= {a:1,b:2,c:3,d:4,e:5,f:6,g:7,h:8,i:9,j:10,k:11,l:12,m:13,n:14,o:15,p:16,q:17,r:18,s:19,t:20,u:21,v:22,w:23,x:24,y:25,z:26}
type Make<N, A extends any[] = []>
= A['length'] extends N ? A : Make<N, [[], ...A]>
type Hash<S, A extends any[] = []>
= S extends `${infer L}${infer R}` ? Hash<R, [...Make<Ord[keyof Ord & L]>, ...A]> : A['length']
function assertArrayIndex<A extends readonly any[], K extends string>(
array: number extends A['length'] ? A : never,
key: K
) : asserts array is (number extends A['length'] ? A & {key: Hash<K>} & {[P in Hash<K>]: A[number]} : never) {}
type Index<Array> = Array[keyof Array & 'key']
Solution by okayu29 #6292
type Num = ReadonlyArray<0>;
type N0 = readonly [];
type N1 = readonly [0];
type N2 = readonly [0, 0];
type N3 = readonly [0, 0, 0];
type N4 = readonly [0, 0, 0, 0];
type N5 = readonly [0, 0, 0, 0, 0];
type N6 = readonly [0, 0, 0, 0, 0, 0];
type N7 = readonly [0, 0, 0, 0, 0, 0, 0];
type N8 = readonly [0, 0, 0, 0, 0, 0, 0, 0];
type N9 = readonly [0, 0, 0, 0, 0, 0, 0, 0, 0];
/**
* Sum<N3, N4> = N7.
*/
type Sum<N extends Num, M extends Num> = readonly [...N, ...M];
type NA = Sum<N9, N7>;
type NI = Sum<NA, Sum<N9, N5>>;
type NP = Sum<NI, Sum<N9, N8>>;
type NX = Sum<NP, Sum<N9, N4>>;
type Codes = {
' ': N7;
a: Sum<NA, N1>;
b: Sum<NA, N2>;
c: Sum<NA, N3>;
d: Sum<NA, N4>;
e: Sum<NA, N5>;
f: Sum<NA, N6>;
g: Sum<NA, N7>;
h: Sum<NA, N8>;
i: Sum<NI, N1>;
j: Sum<NI, N2>;
k: Sum<NI, N3>;
l: Sum<NI, N4>;
m: Sum<NI, N5>;
n: Sum<NI, N6>;
o: Sum<NI, N7>;
p: Sum<NP, N1>;
q: Sum<NP, N2>;
r: Sum<NP, N3>;
s: Sum<NP, N4>;
t: Sum<NP, N5>;
u: Sum<NP, N6>;
v: Sum<NP, N7>;
w: Sum<NP, N9>;
x: Sum<NX, N1>;
y: Sum<NX, N2>;
z: Sum<NX, N3>;
};
/**
* KeyToNum<'ab'> = N74.
*/
type KeyToNum<Key extends string> = Key extends ''
? N0
: Key extends `${infer L}${infer Rest}`
? L extends keyof Codes
? Sum<Codes[L], KeyToNum<Rest>>
: never
: never;
/**
* IsArray<[0]> = false, IsArray<string[]> = true.
*/
type IsArray<A extends readonly unknown[]> = number extends A['length'] ? true : false;
/**
* IsKey<'ab x'> = true, IsKey<'key!'> = false.
*/
type IsKey<Key extends string> = Key extends ''
? false
: KeyToNum<Key> extends never
? false
: true;
declare const KEY: unique symbol;
declare const CODE: unique symbol;
/**
* WithIndex<string, 'foo'> = object with key index 'foo'.
*/
type WithIndex<
Element,
Key extends string,
KeyCode extends number = KeyToNum<Key>['length']
> = KeyCode extends never
? never
: {
readonly [KEY]: Key;
readonly [CODE]: KeyCode;
} & {
readonly [K in KeyCode]: Element;
};
/**
* Index<typeof indexedArray> = index of indexedArray.
*/
type Index<A extends { readonly [CODE]: number }> = A[typeof CODE];
/**
* assertArrayIndex(arr, 'foo') assert that arr is array with key index 'foo'.
*/
function assertArrayIndex<A extends readonly unknown[], Key extends string>(
array: IsKey<Key> extends true ? (IsArray<A> extends true ? A : never) : never,
key: Key,
): asserts array is IsKey<Key> extends true
? IsArray<A> extends true
? A & WithIndex<A[number], Key>
: never
: never {}
Solution by uid11 #946