Lodash Set 的 TypeScript 类型安全版本?

问题描述 投票:0回答:1

有没有办法为 Lodash 的 set 函数添加 TypeScript 类型安全?

我需要为深度嵌套的对象设置值。属性可以是未定义的,我不想覆盖其他对象属性。

此代码有效:

import set from "lodash/set";

type Res = {
  position?: {
    top?: { value: number },
    right?: { value: number }
  },
  color?: {
    red?: number,
    blue?: number
  }
};

const res : Res = {};

const items = ["p-top-1", "p-right-2", 'c-red-300'];

for (let i = 0; i < items.length; i++) {
  const item = items[i];
  const [type, key, value] = item.split('-');

  if(type === 'p') {
    set(res, `position.${key}.value`, value);
  }

  if(type === 'c') {
    set(res, `color.${key}.value`, value);
  }
}

但是它没有类型安全,例如这不会出错:

  if(type === 'p') {
    set(res, `whatever-key-here.${key}.value`, value);
  }
typescript lodash
1个回答
0
投票

set
中有类似的功能
moderndash
,但它缺少类型安全的
set-existing-value
对应物

(它的工作原理与

lodash
set
完全一样,所以你可以自由地
import { set as setUntyped } from "lodash"
代替)

通过将其类型修改为 a-la-

set
而不是 a-la-
assign
,如何实现
set
的类型安全版本就很简单了:

import { set as setUntyped } from "moderndash";
import type { Call, Objects, Strings } from "hotscript";
import type { PlainObject } from "moderndash";
export function set<TObj extends PlainObject, TPath extends Call<Objects.AllPaths, TObj>>(
    obj: TObj, path: TPath, value: Call<Objects.Get<TPath>, TObj>
): TObj {
    return setUntyped(obj, path, value) as TObj
}

要将它与拆分的字符串一起使用,您还需要一个

string.split
重载:

declare global {
    interface String {
        // typesafe 's-t-r-i-n-g'.split('-'): ['s', 't', 'r', 'i', 'n', 'g']
        split<S extends string, D extends string>(this: S, separator: D): Call<Strings.Split<D>, S>;
    }
}

然后示例代码显示错误,正如预期的那样: 游乐场:https://tsplay.dev/Nn886W

const res: Res = {};

const items = ["p-top-1", "p-right-2", 'c-red-300'] as const;

for (let i = 0; i < items.length; i++) {
    const item = items[i];
    const [type, key, value] = item.split('-')

    if (type === 'p') {
        set(res, `position.${key}.value`, value);
        //                                 ^!
        // Argument of type '"1" | "2"' is not assignable to parameter of type 'number | undefined'.
    }

    if (type === 'c') {
        set(res, `color.${key}.value`, value);
        //                              ^!
        // Argument of type '"300"' is not assignable to parameter of type 'undefined'.(2345)
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.