radash
Object.assign
override
initial
import { assign } from 'radash'
const ra = {
name: 'Ra',
power: 100
}
assign(ra, { name: 'Loki' })
// => { name: Loki, power: 100 }
// 定义一个泛型函数 `assign`。
export const assign = <X extends Record<string | symbol | number, any>>(
// `initial` 是初始对象,它的属性可能被 `override` 对象中的属性覆盖。
initial: X,
// `override` 是覆盖对象,其属性将覆盖或添加到 `initial` 对象中。
override: X
): X => {
// 如果 `initial` 或 `override` 为空,则返回非空的那个,或者如果都为空则返回一个空对象。
if (!initial || !override) return initial ?? override ?? {}
// 使用 `Object.entries` 和 `reduce` 方法合并 `initial` 和 `override` 对象。
return Object.entries({ ...initial, ...override }).reduce(
(acc, [key, value]) => {
// 在每次迭代中,构建累加器 `acc`,它是最终返回的新对象。
return {
...acc,
[key]: (() => {
// 如果 `initial` 中的对应属性是一个对象,则递归地调用 `assign` 进行合并。
if (isObject(initial[key])) return assign(initial[key], value)
// 如果属性值是数组,这里有一个注释掉的代码行,似乎是未完成的逻辑。
// if (isArray(value)) return value.map(x => assign)
// 对于非对象属性,直接使用 `override` 中的值。
return value
})()
}
},
{} as X // 初始累加器是一个类型为 `X` 的空对象。
)
}
assign
initial
override
Object.entries
reduce
override
initial
assign
initial
override
initial
override
obj
import { clone } from 'radash'
const ra = {
name: 'Ra',
power: 100
}
const gods = [ra]
clone(ra) // => copy of ra
clone(gods) // => copy of gods
// 定义一个泛型函数 `clone`。
export const clone = <T>(obj: T): T => {
// 如果 `obj` 是原始值(如数字、字符串或布尔值),则不需要克隆,直接返回 `obj`。
if (isPrimitive(obj)) {
return obj
}
// 如果 `obj` 是一个函数,则通过 `bind` 方法创建一个新的绑定函数,
// 并将其绑定到一个空对象上,以创建一个函数的副本。
if (typeof obj === 'function') {
return obj.bind({})
}
// 获取 `obj` 的构造函数,并使用 `new` 操作符创建一个新的对象实例。
// 这个方法同样适用于创建数组的副本。
const newObj = new ((obj as object).constructor as { new (): T })()
// 遍历 `obj` 的所有自有属性,并将它们复制到新对象 `newObj` 中。
Object.getOwnPropertyNames(obj).forEach(prop => {
// 这里使用了类型断言 `(newObj as any)` 和 `(obj as any)` 来绕过类型检查,
// 因为函数开头已经检查了原始值的情况。
;(newObj as any)[prop] = (obj as any)[prop]
})
// 返回新创建的对象 `newObj`。
return newObj
}
obj
obj
bind
obj
obj
newObj
obj
newObj
newObj
obj
import { construct } from 'radash'
const flat = {
name: 'ra',
power: 100,
'friend.name': 'loki',
'friend.power': 80,
'enemies.0.name': 'hathor',
'enemies.0.power': 12
}
construct(flat)
// {
// name: 'ra',
// power: 100,
// friend: {
// name: 'loki',
// power: 80
// },
// enemies: [
// {
// name: 'hathor',
// power: 12
// }
// ]
// }
// 定义一个泛型函数 `construct`。
export const construct = <TObject extends object>(obj: TObject): object => {
// 如果 `obj` 为空,则直接返回一个新的空对象。
if (!obj) return {}
// 使用 `Object.keys` 获取 `obj` 的所有自有属性的键名,
// 然后使用 `reduce` 方法来构建新对象。
return Object.keys(obj).reduce((acc, path) => {
// 对每个属性键名 `path`,调用 `set` 函数来设置新对象 `acc` 的属性。
// `(obj as any)[path]` 获取 `obj` 中对应属性的值。
// `set` 函数的具体实现未提供,我们可以假设它正确地设置了 `acc` 的属性。
return set(acc, path, (obj as any)[path])
}, {}) // 初始累加器 `acc` 是一个空对象。
}
construct
obj
obj
obj
obj
set
obj
obj
import { crush } from 'radash'
const ra = {
name: 'ra',
power: 100,
friend: {
name: 'loki',
power: 80
},
enemies: [
{
name: 'hathor',
power: 12
}
]
}
crush(ra)
// {
// name: 'ra',
// power: 100,
// 'friend.name': 'loki',
// 'friend.power': 80,
// 'enemies.0.name': 'hathor',
// 'enemies.0.power': 12
// }
// 定义一个泛型函数 `crush`。
export const crush = <TValue extends object>(value: TValue): object => {
// 如果 `value` 为空,则直接返回一个空对象。
if (!value) return {}
// 使用 `objectify` 函数来构建新对象。
// `objectify` 函数的具体实现未提供,我们可以假设它以某种方式构建对象。
return objectify(
// 使用 `keys` 函数获取 `value` 的所有键名。
// `keys` 函数的具体实现未提供,我们可以假设它返回对象的所有键名。
keys(value),
// 使用标识函数 `k => k` 作为键生成函数,意味着新对象的键将与原始对象的键相同。
k => k,
// 使用 `get` 函数获取 `value` 对象中每个键对应的值。
// `get` 函数的具体实现未提供,我们可以假设它正确地获取了对象中的属性值。
k => get(value, k)
)
}
crush
value
value
value
keys
value
objectify
k => k
get(value, k)
objectify
value
.
.
import { get } from 'radash'
const fish = {
name: 'Bass',
weight: 8,
sizes: [
{
maturity: 'adult',
range: [7, 18],
unit: 'inches'
}
]
}
get( fish, 'sizes[0].range[1]' ) // 18
get( fish, 'sizes.0.range.1' ) // 18
get( fish, 'foo', 'default' ) // 'default'
// 定义一个泛型函数 `get`。
export const get = <TDefault = unknown>(
// 第一个参数 `value` 是一个任意类型的值,它是要访问属性的对象。
value: any,
// 第二个参数 `path` 是一个字符串,表示对象属性的路径,使用点或方括号表示法。
path: string,
// 第三个可选参数 `defaultValue` 是一个默认值,如果无法访问路径,则返回此值。
defaultValue?: TDefault
): TDefault => {
// 使用正则表达式分割路径字符串,得到一个属性名的数组 `segments`。
const segments = path.split(/[.[]]/g)
// 初始化一个变量 `current`,用于遍历属性路径。
let current: any = value
// 遍历 `segments` 中的每个属性名 `key`。
for (const key of segments) {
// 如果 `current` 是 `null` 或 `undefined`,则返回 `defaultValue`。
if (current === null || current === undefined) return defaultValue as TDefault
// 移除属性名中的引号。
const dequoted = key.replace(/['"]/g, '')
// 如果属性名为空(可能是由于路径字符串中的多余点或方括号),则跳过此迭代。
if (dequoted.trim() === '') continue
// 将 `current` 更新为当前属性名 `dequoted` 对应的值。
current = current[dequoted]
}
// 如果最终的 `current` 是 `undefined`,则返回 `defaultValue`。
if (current === undefined) return defaultValue as TDefault
// 否则,返回找到的值。
return current
}
get
value
path
defaultValue
path
segments
segments
null
undefined
defaultValue
key
value
import { invert } from 'radash'
const powersByGod = {
ra: 'sun',
loki: 'tricks',
zeus: 'lighning'
}
invert(gods) // => { sun: ra, tricks: loki, lightning: zeus }
// 定义一个泛型函数 `invert`。
export const invert = <
// 泛型 `TKey` 表示对象的键的类型。
TKey extends string | number | symbol,
// 泛型 `TValue` 表示对象的值的类型。
TValue extends string | number | symbol
>(
// 参数 `obj` 是一个对象,其键的类型为 `TKey`,值的类型为 `TValue`。
obj: Record<TKey, TValue>
): Record<TValue, TKey> => {
// 如果 `obj` 为空,则返回一个空对象。
if (!obj) return {} as Record<TValue, TKey>
// 使用 `Object.keys` 获取 `obj` 的所有键,并断言键的类型为 `TKey`。
const keys = Object.keys(obj) as TKey[]
// 使用 `reduce` 方法遍历所有键,创建一个新对象,其键为 `obj` 的值,值为 `obj` 的键。
return keys.reduce((acc, key) => {
// 将 `obj` 的值 `obj[key]` 作为新对象 `acc` 的键,原始键 `key` 作为新对象的值。
acc[obj[key]] = key
// 返回累加器 `acc`,它是正在构建的反转对象。
return acc
}, {} as Record<TValue, TKey>) // 初始累加器是一个空对象,类型为 `Record<TValue, TKey>`。
}
invert
obj
obj
obj
obj
obj
obj
key
import { keys } from 'radash'
const ra = {
name: 'ra',
power: 100,
friend: {
name: 'loki',
power: 80
},
enemies: [
{
name: 'hathor',
power: 12
}
]
}
keys(ra)
// => [
// 'name',
// 'power',
// 'friend.name',
// 'friend.power',
// 'enemies.0.name',
// 'enemies.0.power'
// ]
// 定义一个泛型函数 `keys`。
export const keys = <TValue extends object>(value: TValue): string[] => {
// 如果 `value` 为空,则返回一个空数组。
if (!value) return []
// 定义一个递归函数 `getKeys`,用于遍历嵌套对象或数组并获取所有键的路径。
const getKeys = (nested: any, paths: string[]): string[] => {
// 如果当前值 `nested` 是一个对象,递归地遍历它的每一个键值对。
if (isObject(nested)) {
return Object.entries(nested).flatMap(([k, v]) =>
// 对于每一个键值对,将键 `k` 添加到路径数组 `paths` 中,
// 并继续递归地遍历值 `v`。
getKeys(v, [...paths, k])
)
}
// 如果当前值 `nested` 是一个数组,递归地遍历它的每一个元素。
if (isArray(nested)) {
return nested.flatMap((item, i) =>
// 对于每一个元素,将索引 `i` 转换为字符串并添加到路径数组 `paths` 中,
// 然后继续递归地遍历元素 `item`。
getKeys(item, [...paths, `${i}`])
)
}
// 如果当前值 `nested` 既不是对象也不是数组,说明已经到达叶子节点,
// 将路径数组 `paths` 连接成字符串并返回。
return [paths.join('.')]
}
// 使用 `getKeys` 函数从根开始遍历 `value`,并获取所有键的路径。
return getKeys(value, [])
}
keys
value
value
value
getKeys
getKeys
getKeys
getKeys
getKeys
paths
keys
obj
toItem
toItem
import { listify } from 'radash'
const fish = {
marlin: {
weight: 105,
},
bass: {
weight: 8,
}
}
listify(fish, (key, value) => ({ ...value, name: key })) // => [{ name: 'marlin', weight: 105 }, { name: 'bass', weight: 8 }]
// 定义一个泛型函数 `listify`。
export const listify = <TValue, TKey extends string | number | symbol, KResult>(
// 参数 `obj` 是一个对象,其键的类型为 `TKey`,值的类型为 `TValue`。
obj: Record<TKey, TValue>,
// 参数 `toItem` 是一个函数,它接受一个键和一个值,并返回一个新的结果类型 `KResult` 的元素。
toItem: (key: TKey, value: TValue) => KResult
) => {
// 如果 `obj` 为空,则返回一个空数组。
if (!obj) return []
// 使用 `Object.entries` 获取 `obj` 的所有键值对。
const entries = Object.entries(obj)
// 如果 `obj` 没有键值对,返回一个空数组。
if (entries.length === 0) return []
// 使用 `reduce` 方法遍历所有键值对,构建结果数组。
return entries.reduce((acc, entry) => {
// 对每个键值对,调用 `toItem` 函数,并将返回的元素添加到累加器数组 `acc` 中。
acc.push(toItem(entry[0] as TKey, entry[1] as TValue))
// 返回累加器 `acc`。
return acc
}, [] as KResult[]) // 初始累加器是一个空数组,其元素类型为 `KResult`。
}
listify
obj
toItem
obj
obj
Object.entries
obj
obj
obj
reduce
toItem
key
mapKeys
mapKeys
import { lowerize } from 'radash'
const ra = {
Mode: 'god',
Power: 'sun'
}
lowerize(ra) // => { mode, power }
// 定义一个泛型函数 `lowerize`。
export const lowerize = <T extends Record<string, any>>(obj: T) =>
// 调用 `mapKeys` 函数将 `obj` 的所有键转换为小写。
mapKeys(obj, k => k.toLowerCase()) as LowercasedKeys<T>
// `LowercasedKeys<T>` 是一个类型,表示将 `T` 的键转换为小写后的新类型。
// 定义一个泛型函数 `mapKeys`。
export const mapKeys = <
// `TValue` 表示对象的值的类型。
TValue,
// `TKey` 表示对象原始键的类型。
TKey extends string | number | symbol,
// `TNewKey` 表示映射后的新键的类型。
TNewKey extends string | number | symbol
>(
// `obj` 是一个对象,其键的类型为 `TKey`,值的类型为 `TValue`。
obj: Record<TKey, TValue>,
// `mapFunc` 是一个映射函数,它接受一个键和一个值,并返回一个新的键。
mapFunc: (key: TKey, value: TValue) => TNewKey
): Record<TNewKey, TValue> => {
// 使用 `Object.keys` 获取 `obj` 的所有键,并断言键的类型为 `TKey`。
const keys = Object.keys(obj) as TKey[]
// 使用 `reduce` 方法遍历所有键,创建一个新对象,其键为 `mapFunc` 函数的返回值,值为 `obj` 的值。
return keys.reduce((acc, key) => {
// 调用 `mapFunc` 函数获取新键,并将 `obj` 中的值赋给新键。
acc[mapFunc(key as TKey, obj[key])] = obj[key]
// 返回累加器 `acc`,它是正在构建的新对象。
return acc
}, {} as Record<TNewKey, TValue>) // 初始累加器是一个空对象,类型为 `Record<TNewKey, TValue>`。
}
lowerize
obj
mapKeys
obj
mapKeys
obj
mapKeys
obj
lowerize
LowercasedKeys<T>
key
mapKeys
mapFunc
import { upperize } from 'radash'
const ra = {
Mode: 'god',
Power: 'sun'
}
upperize(ra) // => { MODE, POWER }
// 定义一个泛型函数 `upperize`。
export const upperize = <T extends Record<string, any>>(obj: T) =>
// 调用 `mapKeys` 函数将 `obj` 的所有键转换为大写。
mapKeys(obj, k => k.toUpperCase()) as UppercasedKeys<T>
// `UppercasedKeys<T>` 是一个类型,表示将 `T` 的键转换为大写后的新类型。
// 定义一个泛型函数 `mapKeys`。
export const mapKeys = <
// `TValue` 表示对象的值的类型。
TValue,
// `TKey` 表示原始对象的键的类型。
TKey extends string | number | symbol,
// `TNewKey` 表示映射后的新键的类型。
TNewKey extends string | number | symbol
>(
// `obj` 是一个对象,其键的类型为 `TKey`,值的类型为 `TValue`。
obj: Record<TKey, TValue>,
// `mapFunc` 是一个映射函数,它接受一个键和一个值,并返回一个新的键。
mapFunc: (key: TKey, value: TValue) => TNewKey
): Record<TNewKey, TValue> => {
// 使用 `Object.keys` 获取 `obj` 的所有键,并断言它们的类型为 `TKey`。
const keys = Object.keys(obj) as TKey[]
// 使用 `reduce` 方法遍历所有键,创建一个新对象,其键为 `mapFunc` 函数的返回值,值为 `obj` 的值。
return keys.reduce((acc, key) => {
// 调用 `mapFunc` 函数获取新键,并将 `obj` 中的值赋给新键。
acc[mapFunc(key as TKey, obj[key])] = obj[key]
// 返回累加器 `acc`,它是正在构建的新对象。
return acc
}, {} as Record<TNewKey, TValue>) // 初始累加器是一个空对象,类型为 `Record<TNewKey, TValue>`。
}
upperize
obj
mapKeys
obj
mapKeys
obj
mapKeys
obj
upperize
UppercasedKeys<T>
toEntry
obj
toEntry
toEntry
import { mapEntries } from 'radash'
const ra = {
name: 'Ra',
power: 'sun',
rank: 100,
culture: 'egypt'
}
mapEntries(ra, (key, value) => [key.toUpperCase(), `${value}`]) // => { NAME: 'Ra', POWER: 'sun', RANK: '100', CULTURE: 'egypt' }
// 定义一个泛型函数 `mapEntries`。
export const mapEntries = <
// `TKey` 表示原始对象的键的类型。
TKey extends string | number | symbol,
// `TValue` 表示原始对象的值的类型。
TValue,
// `TNewKey` 表示新对象的键的类型。
TNewKey extends string | number | symbol,
// `TNewValue` 表示新对象的值的类型。
TNewValue
>(
// `obj` 是一个对象,其键的类型为 `TKey`,值的类型为 `TValue`。
obj: Record<TKey, TValue>,
// `toEntry` 是一个转换函数,它接受一个键和一个值,并返回一个新的键值对的元组。
toEntry: (key: TKey, value: TValue) => [TNewKey, TNewValue]
): Record<TNewKey, TNewValue> => {
// 如果 `obj` 为空,则返回一个空对象。
if (!obj) return {} as Record<TNewKey, TNewValue>
// 使用 `Object.entries` 获取 `obj` 的所有键值对,并使用 `reduce` 方法来构建新对象。
return Object.entries(obj).reduce((acc, [key, value]) => {
// 对每个键值对,调用 `toEntry` 函数,并获取新键 `newKey` 和新值 `newValue`。
const [newKey, newValue] = toEntry(key as TKey, value as TValue)
// 将新键值对添加到累加器对象 `acc` 中。
acc[newKey] = newValue
// 返回累加器 `acc`。
return acc
}, {} as Record<TNewKey, TNewValue>) // 初始累加器是一个空对象,类型为 `Record<TNewKey, TNewValue>`。
}
mapEntries
obj
toEntry
obj
obj
Object.entries
obj
reduce
toEntry
kye
key
mapFunc
obj
mapFunc
mapFunc
import { mapKeys } from 'radash'
const ra = {
mode: 'god',
power: 'sun'
}
mapKeys(ra, key => key.toUpperCase()) // => { MODE, POWER }
mapKeys(ra, (key, value) => value) // => { god: 'god', power: 'power' }
// 定义一个泛型函数 `mapKeys`。
export const mapKeys = <
// `TValue` 表示对象的值的类型。
TValue,
// `TKey` 表示原始对象的键的类型。
TKey extends string | number | symbol,
// `TNewKey` 表示映射后的新键的类型。
TNewKey extends string | number | symbol
>(
// `obj` 是一个对象,其键的类型为 `TKey`,值的类型为 `TValue`。
obj: Record<TKey, TValue>,
// `mapFunc` 是一个映射函数,它接受一个键和一个值,并返回一个新的键。
mapFunc: (key: TKey, value: TValue) => TNewKey
): Record<TNewKey, TValue> => {
// 使用 `Object.keys` 获取 `obj` 的所有键,并断言它们的类型为 `TKey`。
const keys = Object.keys(obj) as TKey[]
// 使用 `reduce` 方法遍历所有键,创建一个新对象,其键为 `mapFunc` 函数的返回值,值为 `obj` 的值。
return keys.reduce((acc, key) => {
// 调用 `mapFunc` 函数获取新键,并将 `obj` 中的值赋给新键。
acc[mapFunc(key as TKey, obj[key])] = obj[key]
// 返回累加器 `acc`,它是正在构建的新对象。
return acc
}, {} as Record<TNewKey, TValue>) // 初始累加器是一个空对象,类型为 `Record<TNewKey, TValue>`。
}
mapKeys
obj
mapFunc
Object.keys
obj
reduce
mapFunc
obj
value
value
mapFunc
obj
mapFunc
mapFunc
import { clone } from 'radash'
const ra = {
name: 'Ra',
power: 100
}
const gods = [ra]
clone(ra) // => copy of ra
clone(gods) // => copy of gods
// 定义一个泛型函数 `mapValues`。
export const mapValues = <
// `TValue` 表示原始对象的值的类型。
TValue,
// `TKey` 表示对象键的类型。
TKey extends string | number | symbol,
// `TNewValue` 表示映射后的新值的类型。
TNewValue
>(
// `obj` 是一个对象,其键的类型为 `TKey`,值的类型为 `TValue`。
obj: Record<TKey, TValue>,
// `mapFunc` 是一个映射函数,它接受一个值和一个键,并返回一个新的值。
mapFunc: (value: TValue, key: TKey) => TNewValue
): Record<TKey, TNewValue> => {
// 使用 `Object.keys` 获取 `obj` 的所有键,并断言它们的类型为 `TKey`。
const keys = Object.keys(obj) as TKey[]
// 使用 `reduce` 方法遍历所有键,创建一个新对象,其键与 `obj` 相同,值为 `mapFunc` 函数的返回值。
return keys.reduce((acc, key) => {
// 调用 `mapFunc` 函数获取新值,并将其赋给新对象 `acc` 的同名键。
acc[key] = mapFunc(obj[key], key)
// 返回累加器 `acc`,它是正在构建的新对象。
return acc
}, {} as Record<TKey, TNewValue>) // 初始累加器是一个空对象,类型为 `Record<TKey, TNewValue>`。
}
mapValues
obj
mapFunc
Object.keys
obj
reduce
mapFunc
obj
keys
obj
keys
obj
keys
key
import { omit } from 'radash'
const fish = {
name: 'Bass',
weight: 8,
source: 'lake',
brackish: false
}
omit(fish, ['name', 'source']) // => { weight, brackish }
// 定义一个泛型函数 `omit`。
export const omit = <T, TKeys extends keyof T>(
// `obj` 是一个对象,其类型为泛型 `T`。
obj: T,
// `keys` 是一个数组,包含对象 `obj` 中要省略的键名,键名的类型为 `TKeys`。
keys: TKeys[]
): Omit<T, TKeys> => {
// 如果 `obj` 为空,则返回一个空对象。
if (!obj) return {} as Omit<T, TKeys>
// 如果 `keys` 为空或长度为0,则返回原始对象 `obj`。
if (!keys || keys.length === 0) return obj as Omit<T, TKeys>
// 使用 `reduce` 方法遍历 `keys` 数组,从 `obj` 中省略指定的键。
return keys.reduce(
(acc, key) => {
// 在这个较为局限的上下文中,允许直接在累加器对象 `acc` 上使用 `delete` 操作符。
// 这是出于性能考虑,通常不建议在其他地方使用这种模式。
delete acc[key]
// 返回更新后的累加器 `acc`。
return acc
},
// 使用对象展开运算符 `{ ...obj }` 创建 `obj` 的浅拷贝,以避免直接修改原始对象。
{ ...obj }
)
}
omit
obj
keys
obj
keys
obj
keys
reduce
keys
key
delete
acc
obj
keys
obj
keys
key
import { pick } from 'radash'
const fish = {
name: 'Bass',
weight: 8,
source: 'lake',
barckish: false
}
pick(fish, ['name', 'source']) // => { name, source }
// 定义一个泛型函数 `pick`。
export const pick = <T extends object, TKeys extends keyof T>(
// `obj` 是一个对象,其类型为泛型 `T`。
obj: T,
// `keys` 是一个数组,包含对象 `obj` 中要选择的键名,键名的类型为 `TKeys`。
keys: TKeys[]
): Pick<T, TKeys> => {
// 如果 `obj` 为空,则返回一个空对象。
if (!obj) return {} as Pick<T, TKeys>
// 使用 `reduce` 方法遍历 `keys` 数组,从 `obj` 中选择指定的键。
return keys.reduce((acc, key) => {
// 检查 `obj` 是否自身拥有属性 `key`(不是从原型链继承来的)。
if (Object.prototype.hasOwnProperty.call(obj, key))
// 如果 `obj` 拥有 `key`,则将其添加到累加器对象 `acc` 中。
acc[key] = obj[key]
// 返回累加器 `acc`。
return acc
}, {} as Pick<T, TKeys>) // 初始累加器是一个空对象,类型为 `Pick<T, TKeys>`。
}
pick
obj
keys
obj
obj
reduce
keys
key
obj
obj
acc
set
import { set } from 'radash'
set({}, 'name', 'ra')
// => { name: 'ra' }
set({}, 'cards[0].value', 2)
// => { cards: [{ value: 2 }] }
// 定义一个泛型函数 `set`。
export const set = <T extends object, K>(
// `initial` 是初始对象,我们将在其中设置值。
initial: T,
// `path` 是一个字符串,表示要设置值的属性路径。
path: string,
// `value` 是我们要设置在路径上的值。
value: K
): T => {
// 如果 `initial` 为空,则返回一个空对象。
if (!initial) return {} as T
// 如果 `path` 为空或 `value` 未定义,则返回原始对象 `initial`。
if (!path || value === undefined) return initial
// 使用正则表达式分割路径字符串,得到一个属性名的数组 `segments`。
// 过滤掉空字符串,确保所有段都是有效的。
const segments = path.split(/[.[]]/g).filter(x => !!x.trim())
// 定义一个递归辅助函数 `_set`。
const _set = (node: any) => {
// 如果路径 `segments` 有多个段,我们需要深入嵌套结构。
if (segments.length > 1) {
// 弹出当前段的键名 `key`。
const key = segments.shift() as string
// 检查下一个段是否表示数组索引。
const nextIsNum = toInt(segments[0], null) === null ? false : true
// 如果当前键不存在,创建一个新的对象或数组,取决于下一个段是否是数字。
node[key] = node[key] === undefined ? (nextIsNum ? [] : {}) : node[key]
// 递归调用 `_set` 函数,继续设置值。
_set(node[key])
} else {
// 如果路径 `segments` 只有一个段,直接在当前节点上设置值。
node[segments[0]] = value
}
}
// ...(函数的其余部分)
}
set
initial
path
value
initial
path
value
initial
path
segments
_set
segments
segments
segments
_set
initial
obj
filter
true
filter
undefined
import { shake } from 'radash'
const ra = {
mode: 'god',
greek: false,
limit: undefined
}
shake(ra) // => { mode, greek }
shake(ra, a => !a) // => { mode }
// 定义一个泛型函数 `shake`。
export const shake = <RemovedKeys extends string, T>(
// 参数 `obj` 是一个对象,其类型为泛型 `T`。
obj: T,
// 参数 `filter` 是一个可选的函数,用于决定哪些属性应该被省略。
// 默认情况下,它会过滤掉值为 `undefined` 的属性。
filter: (value: any) => boolean = x => x === undefined
): Omit<T, RemovedKeys> => {
// 如果 `obj` 为空,则返回一个空对象。
// 这里返回的类型应该是 `Omit<T, RemovedKeys>` 而不是 `T`。
if (!obj) return {} as Omit<T, RemovedKeys>
// 使用 `Object.keys` 获取 `obj` 的所有键,并将其类型断言为 `T` 的键的类型数组。
const keys = Object.keys(obj) as (keyof T)[]
// 使用 `reduce` 方法遍历所有键,创建一个新对象。
return keys.reduce((acc, key) => {
// 如果 `filter` 函数对当前键的值返回 `true`,则省略该属性。
if (filter(obj[key])) {
return acc
} else {
// 否则,将属性添加到累加器对象 `acc` 中。
acc[key] = obj[key]
return acc
}
}, {} as Omit<T, RemovedKeys>) // 初始累加器是一个空对象,类型为 `Omit<T, RemovedKeys>`。
}
shake
obj
filter
obj
obj
Object.keys
obj
reduce
filter
filter
false
acc
radash