为了账号安全,请及时绑定邮箱和手机立即绑定

如何使用动态对象数组中的键动态键入对象

如何使用动态对象数组中的键动态键入对象

精慕HU 2023-02-24 10:44:58
我有一个函数可以减少属性数组并构建一个对象:type FieldProps = {  name: string;  value: string;  required: boolean;  styles?: object;  className?: string}const fields: FieldProps[] = [  {    name: "firstName",    value: "Bob",    required: true,    styles: { width: "100%"}  },  {    name: "lastName",    value: "Smith",    required: true,    className: "example"  },  {    name: "city",    value: "Tulsa",    required: true,  },  {    name: "state",    value: "OK",    required: true,  },]const parseFields = <T extends any[], K extends object = {}>(fields: T): K => {  try {    if (!fields || (fields && fields.length < 0)) throw new Error("You must supply an array of fields!");    const parsedFields = fields.reduce((acc, { name, value }: { name: string, value: string}) => {      switch (name) {        case "city":        case "street":        case "state":        case "suite":        case "zipCode": {          acc["address"] = acc["address"] || {};          if (value) acc.address[name] = value;          break;        }        default: {          acc[name] = value;          break;        }      }      return acc;    }, {} as K);    return parsedFields;  } catch (err) {    throw String(err);  }};const userDetails = parseFields(fields);截至目前,悬停在上方userDetails会显示一个空对象类型( {}),理想情况下应该是:{  "firstName": string,  "lastName": string,  "address": {    "city": string,    "state": string  }}我如何重构函数以获取类型FieldProps[]并让它返回动态类型的对象?
查看完整描述

3 回答

?
有只小跳蛙

TA贡献1824条经验 获得超8个赞

这个答案非常(过度)复杂,但你最终会得到这种类型:


const userDetails = parseFields(fields);

type Z = typeof userDetails;

// type Z = {

//     address: {

//         city: "Tulsa" | "Norman"; // Added to test

//         state: "OK";

//     };

// } & {

//     firstName: "Bob";

//     lastName: "Smith";

// }

它需要制作fields as const:


const fields = [

  ...

] as const;

还有……实际的打字:


type AddressKeys = 'city' | 'street' | 'state' | 'suite' | 'zipCode';


type _ParseFieldsResultKeys<T extends readonly FieldProps[]> = {

  [K in keyof T]: T[K] extends { name: string } ? T[K]['name'] : never;

}[Exclude<keyof T, keyof []>];


type _GetParseFieldResultValue<T extends readonly FieldProps[], N> =

  Extract<T[keyof T], { name: N }> extends { value: infer V } ? V : never;


type ParseFieldsResult<T extends readonly FieldProps[]> = {

  address: {

    [N in Extract<_ParseFieldsResultKeys<T>, AddressKeys>]: _GetParseFieldResultValue<T, N>;

  }

} & {

  [N in Exclude<_ParseFieldsResultKeys<T>, AddressKeys>]: _GetParseFieldResultValue<T, N>;

};


const parseFields = <T extends readonly FieldProps[]>(fields: T): ParseFieldsResult<T> => {

使用它可能不是一个好主意。但是:游乐场链接


编辑:意识到我们不需要实际的字符串文字类型,只需要string我们可以摆脱_GetParseFieldResultValue并仍然得到的值:


type Z = {

    address: {

        city: string;

        state: string;

    };

} & {

    firstName: string;

    lastName: string;

}


查看完整回答
反对 回复 2023-02-24
?
长风秋雁

TA贡献1757条经验 获得超7个赞

在 parseFields 函数中,你有一个 K.. 的返回类型,它是一个空对象......你不应该传入 FieldProps 吗?

const parseFields = <T extends any[], K extends object = {}>(fields: T): **FieldProps** => {


查看完整回答
反对 回复 2023-02-24
?
智慧大石

TA贡献1946条经验 获得超3个赞

您在此处使用通用方法,并将 K 的默认类型设置为 {},这就是您在悬停时看到 {} 的原因。


您可以通过正确调用该方法来实现您正在寻找的东西。像这样:


const userDetails = parseFields<FieldProps[], {

  "firstName": string,

  "lastName": string,

  "address": {

    "city": string,

    "state": string

  }

}>(fields);  


查看完整回答
反对 回复 2023-02-24
  • 3 回答
  • 0 关注
  • 175 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号