]: T[P] extends object
? Camelize
}[keyof T & (string | number)]
```
### Two Sum
> Given an array of integers `nums` and an integer `target`, return true if two numbers such that they add up to `target`.
```typescript
type TwoSum = any
/* _____________ Test Cases _____________ */
import type { Equal, Expect } from '@type-challenges/utils'
type cases = [
Expect = S extends `${infer F}${infer R}`
? F | StringToUnion> = S extends `${infer F}${infer Rest}`
? F extends U
? DropString = any
/* _____________ Test Cases _____________ */
import type { Equal, Expect } from '@type-challenges/utils'
type cases = [
Expect = SEP extends ''
? S extends `${infer F}${infer R}`
? [F, ...Split` which takes an exact string type `S` consisting 0 and 1 and returns an exact number type corresponding with `S` when `S` is regarded as a binary.
>
> You can assume that the length of `S` is equal to or less than 8 and `S` is not empty.
```typescript
type BinaryToDecimal = any
/* _____________ Test Cases _____________ */
import type { Equal, Expect } from '@type-challenges/utils'
type cases = [
Expect = S extends `${infer F extends number}${infer R}`
? BinaryToDecimal = any
export type Decode = any
}
/* _____________ Test Cases _____________ */
import type { Equal, Expect } from '@type-challenges/utils'
type cases = [
// Raw string -> encoded string
Expect
小镇做题家 - TypeScript 类型大挑战(困难篇 - 下)
## Hard 组(下)
### DeepPick
> Implement a type DeepPick, that extends Utility types `Pick`. A type takes two arguments.
```typescript
type DeepPick = any
/* _____________ Test Cases _____________ */
import type { Equal, Expect } from '@type-challenges/utils'
type Obj = {
a: number
b: string
c: boolean
obj: {
d: number
e: string
f: boolean
obj2: {
g: number
h: string
i: boolean
}
}
obj3: {
j: number
k: string
l: boolean
}
}
type cases = [
Expect, unknown>>,
Expect, { a: number }>>,
Expect, { a: number } & unknown>>,
Expect, { a: number } & { obj: { e: string } }>>,
Expect, { a: number } & { obj: { e: string } } & { obj: { obj2: { i: boolean } } }>>,
]
```
我们可以看到题目中出现了 `obj.e` 、`obj.obj2.i` ,很明显,这需要通过 [Typed Get](#Typed Get) 来取值:
```typescript
type Get = K extends `${infer Key}.${infer R}`
? Key extends keyof T
? Get
: never
: K extends keyof T
? T[K]
: never
```
当然,我们需要对 Get 作一些调整,因为题中是需要一些新的对象作为值:
```typescript
type Get = K extends `${infer Key}.${infer R}`
? Key extends keyof T
? { [P in keyof T as P extends Key ? P : never]: Get }
: never
: K extends keyof T
? { [P in keyof T as P extends K ? P : never ]: T[K] }
: never
```
然后就是结果需要转成交叉类型:
```typescript
/**
* UnionToFunc<1 | 2> => ((arg: 1) => void | (arg: 2) => void)
*/
type UnionToFunc = T extends unknown ? (arg: T) => void : never
/**
* UnionToIntersection<1 | 2> = 1 & 2
*/
type UnionToIntersection = UnionToFunc extends (arg: infer Arg) => void
? Arg
: never
```
最终组合起来即可:
```typescript
type DeepPick = UnionToIntersection>
```
### Pinia
> Create a type-level function whose types is similar to [Pinia](https://github.com/posva/pinia) library. You don't need to implement function actually, just adding types.
```typescript
declare function defineStore(store: unknown): unknown
/* _____________ Test Cases _____________ */
import type { Equal, Expect } from '@type-challenges/utils'
const store = defineStore({
id: '',
state: () => ({
num: 0,
str: '',
}),
getters: {
stringifiedNum() {
// @ts-expect-error
this.num += 1
return this.num.toString()
},
parsedNum() {
return parseInt(this.stringifiedNum)
},
},
actions: {
init() {
this.reset()
this.increment()
},
increment(step = 1) {
this.num += step
},
reset() {
this.num = 0
// @ts-expect-error
this.parsedNum = 0
return true
},
setNum(value: number) {
this.num = value
},
},
})
// @ts-expect-error
store.nopeStateProp
// @ts-expect-error
store.nopeGetter
// @ts-expect-error
store.stringifiedNum()
store.init()
// @ts-expect-error
store.init(0)
store.increment()
store.increment(2)
// @ts-expect-error
store.setNum()
// @ts-expect-error
store.setNum('3')
store.setNum(3)
const r = store.reset()
type _tests = [
Expect>,
Expect>,
Expect>,
Expect>,
Expect>,
]
```
这题需要注意的是,getters 是只读的,同时在 getters 中的 state 也是只读的:
```typescript
type StoreOptions = {
id?: string;
state?: () => State;
getters?: Getters & ThisType & {
readonly [P in keyof Getters]: Getters[P] extends (...args: any) => infer R
? R
: never
}>;
actions?: Actions & ThisType infer R
? R
: never
} & Actions>;
}
declare function defineStore(store: StoreOptions): Readonly & {
readonly [P in keyof Getters]: Getters[P] extends (...args: any) => infer R
? R
: never
} & Actions
```
### Camelize
> Implement Camelize which converts object from snake_case to to camelCase
```typescript
type Camelize = any
/* _____________ Test Cases _____________ */
import type { Equal, Expect } from '@type-challenges/utils'
type cases = [
Expect,
{
someProp: string
prop: { anotherProp: string }
array: [
{ snakeCase: string },
{ anotherElement: { yetAnotherProp: string } },
{ yetAnotherElement: string },
]
}
>>,
]
```
首先需要实现一个将字符串转小陀峰的辅助类:
```typescript
type CamelizeKey = K extends `${infer F}_${infer R}`
? `${F}${CamelizeKey>}`
: K
```
然后区分 Tuple 和 Interface,逐一处理即可:
```typescript
type Camelize = T extends unknown[]
? T extends [infer F, ...infer R]
? [Camelize, ...Camelize]
: []
: {
[P in keyof T as CamelizeKey